changes from H.G. Muller; version 4.3.14
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 57e350e..edccef8 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -119,13 +119,13 @@ ChessSquare PromoPiece(moveType)
        return BlackKing;\r
 #ifdef FAIRY\r
       case WhitePromotionChancellor:\r
-        return WhiteFairyRook;\r
+        return WhiteMarshall;\r
       case BlackPromotionChancellor:\r
-        return BlackFairyRook;\r
+        return BlackMarshall;\r
       case WhitePromotionArchbishop:\r
-        return WhiteFairyBishop;\r
+        return WhiteCardinal;\r
       case BlackPromotionArchbishop:\r
-        return BlackFairyBishop;\r
+        return BlackCardinal;\r
 #endif\r
     }\r
 }\r
@@ -196,65 +196,36 @@ ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
 }\r
 \r
 char pieceToChar[] = {\r
-    'P', 'N', 'B', 'R', \r
-#ifdef FAIRY\r
-    'A', 'C', 'F', 'H', 'E', 'W', 'D', 'O', 'G', 'M',\r
-#endif\r
-    'Q', 'K', 'p', 'n', 'b', 'r', \r
-#ifdef FAIRY            \r
-    'a', 'c', 'f', 'h', 'e', 'w', 'd', 'o', 'g', 'm',\r
-#endif\r
-    'q', 'k', 'x'\r
-  };\r
+                        'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', \r
+                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'S', 'L', 'U', 'K',\r
+                        'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', \r
+                        'o', 'h', 'i', 'j', 'g', 'd', 'v', 's', 'l', 'u', 'k', \r
+                        'x' };\r
 \r
 char PieceToChar(p)\r
      ChessSquare p;\r
 {\r
+    if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */\r
     return pieceToChar[(int) p];\r
 }\r
 \r
+int PieceToNumber(p)  /* [HGM] holdings: count piece type, ignoring non-participating piece types */\r
+     ChessSquare p;\r
+{\r
+    int i=0;\r
+    ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn;\r
+\r
+    while(start++ != p) if(pieceToChar[(int)start-1] != '.') i++;\r
+    return i;\r
+}\r
+\r
 ChessSquare CharToPiece(c)\r
      int c;\r
-{    switch (c) {\r
-      default:\r
-      case 'x':        return EmptySquare;\r
-      case 'P':        return WhitePawn;\r
-      case 'R':        return WhiteRook;\r
-      case 'N':        return WhiteKnight;\r
-      case 'B':        return WhiteBishop;\r
-      case 'Q':        return WhiteQueen;\r
-      case 'K':        return WhiteKing;\r
-      case 'p':        return BlackPawn;\r
-      case 'r':        return BlackRook;\r
-      case 'n':        return BlackKnight;\r
-      case 'b':        return BlackBishop;\r
-      case 'q':        return BlackQueen;\r
-      case 'k':        return BlackKing;\r
-#ifdef FAIRY\r
-      case 'A': return WhiteCardinal;\r
-      case 'C': return WhiteMarshall;\r
-      case 'F': return WhiteFairyPawn;\r
-      case 'H': return WhiteFairyKnight;\r
-      case 'E': return WhiteFairyBishop;\r
-      case 'W': return WhiteFairyRook;\r
-      case 'D': return WhiteFairyCardinal;\r
-      case 'O': return WhiteFairyMarshall;\r
-      case 'G': return WhiteFairyQueen;\r
-      case 'M': return WhiteFairyKing;\r
-                \r
-      case 'a': return BlackCardinal;\r
-      case 'c': return BlackMarshall;\r
-      case 'f': return BlackFairyPawn;\r
-      case 'h': return BlackFairyKnight;\r
-      case 'e': return BlackFairyBishop;\r
-      case 'w': return BlackFairyRook;\r
-      case 'd': return BlackFairyCardinal;\r
-      case 'o': return BlackFairyMarshall;\r
-      case 'g': return BlackFairyQueen;\r
-      case 'm': return BlackFairyKing;\r
-                \r
-#endif\r
-    }\r
+{\r
+     int i;\r
+     for(i=0; i< (int) EmptySquare; i++)\r
+          if(pieceToChar[i] == c) return (ChessSquare) i;\r
+     return EmptySquare;\r
 }\r
 \r
 void CopyBoard(to, from)\r
@@ -300,21 +271,27 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
     int i, j, d, s, fs, rs, rt, ft, m;\r
 \r
     for (rf = 0; rf < BOARD_HEIGHT; rf++) \r
-      for (ff = 0; ff < BOARD_WIDTH; ff++) {\r
+      for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {\r
+          ChessSquare piece;\r
+\r
          if (flags & F_WHITE_ON_MOVE) {\r
              if (!WhitePiece(board[rf][ff])) continue;\r
          } else {\r
              if (!BlackPiece(board[rf][ff])) continue;\r
          }\r
-          m = 0;\r
-         switch (board[rf][ff]) {\r
-           case EmptySquare:\r
+          m = 0; piece = board[rf][ff];\r
+          if(PieceToChar(piece) == '~') \r
+                 piece = (ChessSquare) ( DEMOTED piece );\r
+          if(gameInfo.variant == VariantShogi)\r
+                 piece = (ChessSquare) ( SHOGI piece );\r
+\r
+          switch (piece) {\r
+            /* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */\r
            default:\r
              /* can't happen ([HGM] except for faries...) */\r
              break;\r
 \r
-           case WhitePawn:\r
-#ifdef FAIRY\r
+             case WhitePawn:\r
               if(gameInfo.variant == VariantXiangqi) {\r
                   /* [HGM] capture and move straight ahead in Xiangqi */\r
                   if (rf < BOARD_HEIGHT-1 &&\r
@@ -325,7 +302,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                   /* and move sideways when across the river */\r
                   for (s = -1; s <= 1; s += 2) {\r
                       if (rf >= BOARD_HEIGHT>>1 &&\r
-                          ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                          ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
                           !WhitePiece(board[rf][ff+s]) ) {\r
                            callback(board, flags, NormalMove,\r
                                     rf, ff, rf, ff+s, closure);\r
@@ -333,7 +310,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                   }\r
                   break;\r
               }\r
-#endif\r
               if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {\r
                  callback(board, flags,\r
                           rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
@@ -341,12 +317,13 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              }\r
              if (rf == 1 && board[2][ff] == EmptySquare &&\r
                   gameInfo.variant != VariantShatranj && /* [HGM] */\r
+                  gameInfo.variant != VariantCourier  && /* [HGM] */\r
                   board[3][ff] == EmptySquare ) {\r
                       callback(board, flags, NormalMove,\r
                                rf, ff, 3, ff, closure);\r
              }\r
              for (s = -1; s <= 1; s += 2) {\r
-                 if (rf < BOARD_HEIGHT-1 && ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
                      ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
                       BlackPiece(board[rf + 1][ff + s]))) {\r
                      callback(board, flags, \r
@@ -354,7 +331,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                               rf, ff, rf + 1, ff + s, closure);\r
                  }\r
                  if (rf == BOARD_HEIGHT-4) {\r
-                     if (ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                      if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
                          (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
                           board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&\r
                           board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {\r
@@ -366,7 +343,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              break;\r
 \r
            case BlackPawn:\r
-#ifdef FAIRY\r
               if(gameInfo.variant == VariantXiangqi) {\r
                   /* [HGM] capture straight ahead in Xiangqi */\r
                   if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {\r
@@ -376,7 +352,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                   /* and move sideways when across the river */\r
                   for (s = -1; s <= 1; s += 2) {\r
                       if (rf < BOARD_HEIGHT>>1 &&\r
-                          ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                          ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
                           !BlackPiece(board[rf][ff+s]) ) {\r
                            callback(board, flags, NormalMove,\r
                                     rf, ff, rf, ff+s, closure);\r
@@ -384,7 +360,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                   }\r
                   break;\r
               }\r
-#endif\r
              if (rf > 0 && board[rf - 1][ff] == EmptySquare) {\r
                  callback(board, flags, \r
                           rf == 1 ? BlackPromotionQueen : NormalMove,\r
@@ -392,12 +367,13 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              }\r
              if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&\r
                   gameInfo.variant != VariantShatranj && /* [HGM] */\r
+                  gameInfo.variant != VariantCourier  && /* [HGM] */\r
                  board[BOARD_HEIGHT-4][ff] == EmptySquare) {\r
                  callback(board, flags, NormalMove,\r
                           rf, ff, BOARD_HEIGHT-4, ff, closure);\r
              }\r
              for (s = -1; s <= 1; s += 2) {\r
-                 if (rf > 0 && ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
                      ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
                       WhitePiece(board[rf - 1][ff + s]))) {\r
                      callback(board, flags, \r
@@ -405,7 +381,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                               rf, ff, rf - 1, ff + s, closure);\r
                  }\r
                  if (rf == 3) {\r
-                      if (ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                      if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
                          (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
                          board[3][ff + s] == WhitePawn &&\r
                          board[2][ff + s] == EmptySquare) {\r
@@ -416,6 +392,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              }             \r
              break;\r
 \r
+            case WhiteUnicorn:\r
+            case BlackUnicorn:\r
            case WhiteKnight:\r
            case BlackKnight:\r
             mounted:\r
@@ -424,22 +402,43 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                  for (s = 1; s <= 2; s++) {\r
                      rt = rf + i*s;\r
                      ft = ff + j*(3-s);\r
-                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) continue;\r
-                     if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)\r
+                          && ( gameInfo.variant != VariantXiangqi || board[rf+i*(s-1)][ff+j*(2-s)] == EmptySquare)\r
+                          && !SameColor(board[rf][ff], board[rt][ft]))\r
                      callback(board, flags, NormalMove,\r
                               rf, ff, rt, ft, closure);\r
                  }\r
              break;\r
-#ifdef FAIRY\r
-            case WhiteFairyMarshall:\r
-            case BlackFairyMarshall:\r
+\r
+            case SHOGI WhiteKnight:\r
+             for (s = -1; s <= 1; s += 2) {\r
+                  if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
+                      !SameColor(board[rf][ff], board[rf + 2][ff + s])) {\r
+                      callback(board, flags, NormalMove,\r
+                               rf, ff, rf + 2, ff + s, closure);\r
+                 }\r
+              }\r
+             break;\r
+\r
+            case SHOGI BlackKnight:\r
+             for (s = -1; s <= 1; s += 2) {\r
+                  if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
+                      !SameColor(board[rf][ff], board[rf - 2][ff + s])) {\r
+                      callback(board, flags, NormalMove,\r
+                               rf, ff, rf - 2, ff + s, closure);\r
+                 }\r
+             }             \r
+             break;\r
+\r
+            case WhiteCannon:\r
+            case BlackCannon:\r
               for (d = 0; d <= 1; d++)\r
                 for (s = -1; s <= 1; s += 2) {\r
                   m = 0;\r
                  for (i = 1;; i++) {\r
                      rt = rf + (i * s) * d;\r
                      ft = ff + (i * s) * (1 - d);\r
-                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
                       if (m == 0 && board[rt][ft] == EmptySquare)\r
                                  callback(board, flags, NormalMove,\r
                                           rf, ff, rt, ft, closure);\r
@@ -452,36 +451,80 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                 }\r
              break;\r
 \r
-            case WhiteFairyRook:\r
-            case BlackFairyRook:\r
+            /* Gold General (and all its promoted versions) . First do the */\r
+            /* diagonal forward steps, then proceed as normal Wazir        */\r
+            case SHOGI WhiteWazir:\r
+            case SHOGI (PROMOTED WhitePawn):\r
+            case SHOGI (PROMOTED WhiteKnight):\r
+            case SHOGI (PROMOTED WhiteQueen):\r
+            case SHOGI (PROMOTED WhiteFerz):\r
+             for (s = -1; s <= 1; s += 2) {\r
+                  if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
+                      !SameColor(board[rf][ff], board[rf + 1][ff + s])) {\r
+                      callback(board, flags, NormalMove,\r
+                              rf, ff, rf + 1, ff + s, closure);\r
+                 }\r
+              }\r
+              goto finishGold;\r
+\r
+            case SHOGI BlackWazir:\r
+            case SHOGI (PROMOTED BlackPawn):\r
+            case SHOGI (PROMOTED BlackKnight):\r
+            case SHOGI (PROMOTED BlackQueen):\r
+            case SHOGI (PROMOTED BlackFerz):\r
+             for (s = -1; s <= 1; s += 2) {\r
+                  if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&\r
+                      !SameColor(board[rf][ff], board[rf - 1][ff + s])) {\r
+                      callback(board, flags, NormalMove,\r
+                              rf, ff, rf - 1, ff + s, closure);\r
+                 }\r
+             }             \r
+\r
+            case WhiteWazir:\r
+            case BlackWazir:\r
+            finishGold:\r
               for (d = 0; d <= 1; d++)\r
-                for (s = -1; s <= 1; s += 2)\r
+                for (s = -1; s <= 1; s += 2) {\r
                       rt = rf + s * d;\r
                       ft = ff + s * (1 - d);\r
-                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH)\r
-                          && !SameColor(board[rf][ff], board[rt][ft]))\r
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)\r
+                          && !SameColor(board[rf][ff], board[rt][ft]) &&\r
+                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )\r
                                callback(board, flags, NormalMove,\r
                                         rf, ff, rt, ft, closure);\r
+                      }\r
              break;\r
 \r
-           case WhiteFairyBishop:\r
-           case BlackFairyBishop:\r
+            case WhiteAlfil:\r
+            case BlackAlfil:\r
                 /* [HGM] support Shatranj pieces */\r
                 for (rs = -1; rs <= 1; rs += 2) \r
                   for (fs = -1; fs <= 1; fs += 2) {\r
                       rt = rf + 2 * rs;\r
                       ft = ff + 2 * fs;\r
-                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH)\r
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)\r
+                          && ( gameInfo.variant != VariantXiangqi ||\r
+                               board[rf+rs][ff+fs] == EmptySquare && (2*rf < BOARD_HEIGHT) == (2*rt < BOARD_HEIGHT) )\r
+                         \r
                           && !SameColor(board[rf][ff], board[rt][ft]))\r
                                callback(board, flags, NormalMove,\r
                                         rf, ff, rt, ft, closure);\r
                  }\r
                 break;\r
 \r
-            case WhiteCardinal:\r
-            case BlackCardinal:\r
+            /* Shogi Dragon Horse has to continue with Wazir after Bishop */\r
+            case SHOGI WhiteCardinal:\r
+            case SHOGI BlackCardinal:\r
               m++;\r
-#endif\r
+\r
+            /* Capablanca Archbishop continues as Knight                  */\r
+            case WhiteAngel:\r
+            case BlackAngel:\r
+              m++;\r
+\r
+            /* Shogi Bishops are ordinary Bishops */\r
+            case SHOGI WhiteBishop:\r
+            case SHOGI BlackBishop:\r
            case WhiteBishop:\r
            case BlackBishop:\r
              for (rs = -1; rs <= 1; rs += 2) \r
@@ -489,20 +532,55 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                  for (i = 1;; i++) {\r
                      rt = rf + (i * rs);\r
                      ft = ff + (i * fs);\r
-                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
                      if (SameColor(board[rf][ff], board[rt][ft])) break;\r
                      callback(board, flags, NormalMove,\r
                               rf, ff, rt, ft, closure);\r
                      if (board[rt][ft] != EmptySquare) break;\r
                  }\r
-                if(m) goto mounted;\r
+                if(m==1) goto mounted;\r
+                if(m==2) goto finishGold;\r
+                /* Bishop falls through */\r
              break;\r
 \r
-#ifdef FAIRY\r
+            /* Shogi Lance is unlike anything, and asymmetric at that */\r
+            case SHOGI WhiteQueen:\r
+              for(i = 1;; i++) {\r
+                      rt = rf + i;\r
+                      ft = ff;\r
+                      if (rt >= BOARD_HEIGHT) break;\r
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
+                     callback(board, flags, NormalMove,\r
+                              rf, ff, rt, ft, closure);\r
+                      if (board[rt][ft] != EmptySquare) break;\r
+              }\r
+              break;\r
+\r
+            case SHOGI BlackQueen:\r
+              for(i = 1;; i++) {\r
+                      rt = rf - i;\r
+                      ft = ff;\r
+                      if (rt < 0) break;\r
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
+                     callback(board, flags, NormalMove,\r
+                              rf, ff, rt, ft, closure);\r
+                      if (board[rt][ft] != EmptySquare) break;\r
+              }\r
+              break;\r
+\r
+            /* Shogi Dragon King has to continue as Ferz after Rook moves */\r
+            case SHOGI WhiteDragon:\r
+            case SHOGI BlackDragon:\r
+              m++;\r
+\r
+            /* Capablanca Chancellor sets flag to continue as Knight      */\r
             case WhiteMarshall:\r
             case BlackMarshall:\r
               m++;\r
-#endif\r
+\r
+            /* Shogi Rooks are ordinary Rooks */\r
+            case SHOGI WhiteRook:\r
+            case SHOGI BlackRook:\r
            case WhiteRook:\r
            case BlackRook:\r
               for (d = 0; d <= 1; d++)\r
@@ -510,13 +588,14 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                  for (i = 1;; i++) {\r
                      rt = rf + (i * s) * d;\r
                      ft = ff + (i * s) * (1 - d);\r
-                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
                      if (SameColor(board[rf][ff], board[rt][ft])) break;\r
                      callback(board, flags, NormalMove,\r
                               rf, ff, rt, ft, closure);\r
                      if (board[rt][ft] != EmptySquare) break;\r
                  }\r
-                if(m) goto mounted;\r
+                if(m==1) goto mounted;\r
+                if(m==2) goto walking;\r
              break;\r
 \r
            case WhiteQueen:\r
@@ -527,7 +606,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                    for (i = 1;; i++) {\r
                        rt = rf + (i * rs);\r
                        ft = ff + (i * fs);\r
-                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                        if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
                        if (SameColor(board[rf][ff], board[rt][ft])) break;\r
                        callback(board, flags, NormalMove,\r
                                 rf, ff, rt, ft, closure);\r
@@ -536,37 +615,77 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                }\r
              break;\r
 \r
-#ifdef FAIRY\r
-            case WhiteFairyPawn:\r
-            case BlackFairyPawn:\r
+            /* Shogi Pawn and Silver General: first the Pawn move,    */\r
+            /* then the General continues like a Ferz                 */\r
+            case SHOGI WhitePawn:\r
+            case SHOGI WhiteFerz:\r
+                  if (rf < BOARD_HEIGHT-1 &&\r
+                           !SameColor(board[rf][ff], board[rf + 1][ff]) ) \r
+                           callback(board, flags, NormalMove,\r
+                                    rf, ff, rf + 1, ff, closure);\r
+              if(piece != SHOGI WhitePawn) goto finishSilver;\r
+              break;\r
+\r
+            case SHOGI BlackPawn:\r
+            case SHOGI BlackFerz:\r
+                  if (rf > 0 &&\r
+                           !SameColor(board[rf][ff], board[rf - 1][ff]) ) \r
+                           callback(board, flags, NormalMove,\r
+                                    rf, ff, rf - 1, ff, closure);\r
+              if(piece == SHOGI BlackPawn) break;\r
+\r
+            case WhiteFerz:\r
+            case BlackFerz:\r
+            finishSilver:\r
                 /* [HGM] support Shatranj pieces */\r
                 for (rs = -1; rs <= 1; rs += 2) \r
                   for (fs = -1; fs <= 1; fs += 2) {\r
                       rt = rf + rs;\r
                       ft = ff + fs;\r
-                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
-                      if (!SameColor(board[rf][ff], board[rt][ft]))\r
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;\r
+                      if (!SameColor(board[rf][ff], board[rt][ft]) &&\r
+                          (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) )\r
                                callback(board, flags, NormalMove,\r
                                         rf, ff, rt, ft, closure);\r
                  }\r
                 break;\r
 \r
-            case WhiteFairyKing:\r
-            case BlackFairyKing:\r
-#endif\r
+            case WhiteMan:\r
+            case BlackMan:\r
+            case SHOGI WhiteKing:\r
+            case SHOGI BlackKing:\r
            case WhiteKing:\r
            case BlackKing:\r
+            walking:\r
              for (i = -1; i <= 1; i++)\r
                for (j = -1; j <= 1; j++) {\r
                    if (i == 0 && j == 0) continue;\r
                    rt = rf + i;\r
                    ft = ff + j;\r
-                   if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) continue;\r
+                    if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;\r
                    if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
                    callback(board, flags, NormalMove,\r
                             rf, ff, rt, ft, closure);\r
                }\r
              break;\r
+\r
+           case WhiteNightrider:\r
+           case BlackNightrider:\r
+             for (i = -1; i <= 1; i += 2)\r
+               for (j = -1; j <= 1; j += 2)\r
+                 for (s = 1; s <= 2; s++) {  int k;\r
+                    for(k=1;; k++) {\r
+                     rt = rf + k*i*s;\r
+                     ft = ff + k*j*(3-s);\r
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\r
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
+                     callback(board, flags, NormalMove,\r
+                              rf, ff, rt, ft, closure);\r
+                     if (board[rt][ft] != EmptySquare) break;\r
+                    }\r
+                 }\r
+             break;\r
+\r
          }\r
       }\r
 }\r
@@ -602,7 +721,7 @@ void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
        if (board[rf][ff] == king) return;\r
        for (r = rt-1; r <= rt+1; r++) {\r
          for (f = ft-1; f <= ft+1; f++) {\r
-           if (r >= 0 && r < BOARD_HEIGHT && f >= 0 && f < BOARD_WIDTH &&\r
+            if (r >= 0 && r < BOARD_HEIGHT && f >= BOARD_LEFT && f < BOARD_RGHT &&\r
                board[r][f] == king) return;\r
          }\r
        }\r
@@ -634,8 +753,9 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
      VOIDSTAR closure;\r
 {\r
     GenLegalClosure cl;\r
-    int ff, ft;\r
+    int ff, ft, k, left, right;\r
     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;\r
+    ChessSquare wKing = WhiteKing, bKing = BlackKing;\r
 \r
     cl.cb = callback;\r
     cl.cl = closure;\r
@@ -645,120 +765,156 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
        CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;\r
 \r
     /* Generate castling moves */\r
+    if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */\r
+        wKing = WhiteUnicorn; bKing = BlackUnicorn;\r
+    }\r
+\r
     for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {\r
        if ((flags & F_WHITE_ON_MOVE) &&\r
            (flags & F_WHITE_KCASTLE_OK) &&\r
-           board[0][ff] == WhiteKing &&\r
-           board[0][ff + 1] == EmptySquare &&\r
-           board[0][ff + 2] == EmptySquare &&\r
-           board[0][BOARD_WIDTH-3] == EmptySquare &&\r
-           board[0][BOARD_WIDTH-2] == EmptySquare &&\r
-           board[0][BOARD_WIDTH-1] == WhiteRook &&\r
+            board[0][ff] == wKing &&\r
+            board[0][ff + 1] == EmptySquare &&\r
+            board[0][ff + 2] == EmptySquare &&\r
+            board[0][BOARD_RGHT-3] == EmptySquare &&\r
+            board[0][BOARD_RGHT-2] == EmptySquare &&\r
+            board[0][BOARD_RGHT-1] == WhiteRook &&\r
             castlingRights[0] >= 0 && /* [HGM] check rights */\r
             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
             (ignoreCheck ||                             \r
             (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&\r
-             !CheckTest(board, flags, 0, ff, 0, BOARD_WIDTH-3, FALSE) &&\r
+              !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) &&\r
+              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-2, FALSE)) &&\r
              !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
-                    ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
-                    0, ff, 0, ff + ((BOARD_WIDTH+2)>>2), closure);\r
+                     ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
+                     0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);\r
        }\r
        if ((flags & F_WHITE_ON_MOVE) &&\r
            (flags & F_WHITE_QCASTLE_OK) &&\r
-           board[0][ff] == WhiteKing &&\r
+            board[0][ff] == wKing &&\r
            board[0][ff - 1] == EmptySquare &&\r
            board[0][ff - 2] == EmptySquare &&\r
-           board[0][2] == EmptySquare &&\r
-           board[0][1] == EmptySquare &&\r
-            board[0][0] == WhiteRook &&\r
+            board[0][BOARD_LEFT+2] == EmptySquare &&\r
+            board[0][BOARD_LEFT+1] == EmptySquare &&\r
+            board[0][BOARD_LEFT+0] == WhiteRook &&\r
             castlingRights[1] >= 0 && /* [HGM] check rights */\r
             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
            (ignoreCheck ||\r
             (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&\r
-             !CheckTest(board, flags, 0, ff, 0, 3,      FALSE) &&\r
+              !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) &&\r
              !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
                     ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,\r
-                    0, ff, 0, ff - ((BOARD_WIDTH+2)>>2), closure);\r
+                     0, ff, 0, ff - ((gameInfo.boardWidth+2)>>2), closure);\r
        }\r
        if (!(flags & F_WHITE_ON_MOVE) &&\r
            (flags & F_BLACK_KCASTLE_OK) &&\r
-           board[BOARD_HEIGHT-1][ff] == BlackKing &&\r
+            board[BOARD_HEIGHT-1][ff] == bKing &&\r
            board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&\r
            board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][BOARD_WIDTH-3] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][BOARD_WIDTH-2] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][BOARD_WIDTH-1] == BlackRook &&\r
+            board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare &&\r
+            board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare &&\r
+            board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook &&\r
             castlingRights[3] >= 0 && /* [HGM] check rights */\r
             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
            (ignoreCheck ||\r
             (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&\r
-             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_WIDTH-3, FALSE) &&\r
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) &&\r
+              (gameInfo.variant != VariantJanus || !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-2, FALSE)) &&\r
              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
                     ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,\r
-                    BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((BOARD_WIDTH+2)>>2), closure);\r
+                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure);\r
        }\r
        if (!(flags & F_WHITE_ON_MOVE) &&\r
            (flags & F_BLACK_QCASTLE_OK) &&\r
-           board[BOARD_HEIGHT-1][ff] == BlackKing &&\r
+            board[BOARD_HEIGHT-1][ff] == bKing &&\r
            board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&\r
            board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][2] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][1] == EmptySquare &&\r
-           board[BOARD_HEIGHT-1][0] == BlackRook &&\r
+            board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare &&\r
+            board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare &&\r
+            board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook &&\r
             castlingRights[4] >= 0 && /* [HGM] check rights */\r
             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
            (ignoreCheck ||\r
             (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&\r
-             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, 3,      FALSE) &&\r
-             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE)))) {\r
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) &&\r
+              !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
                     ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,\r
-                    BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((BOARD_WIDTH+2)>>2), closure);\r
+                     BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((gameInfo.boardWidth+2)>>2), closure);\r
        }\r
     }\r
 \r
-    /* PUSH Fabien */\r
+  if(gameInfo.variant == VariantFischeRandom) {\r
 \r
     /* generate all potential FRC castling moves (KxR), ignoring flags */\r
-    /* [HGM] Tord! Help requested! */\r
+    /* [HGM] test if the Rooks we find have castling rights */\r
 \r
-    if ((flags & F_WHITE_ON_MOVE) != 0) {\r
-\r
-       for (ff = 1; ff < BOARD_WIDTH-1; ff++) {\r
-          if (board[0][ff] == WhiteKing) {\r
-             for (ft = 0; ft < BOARD_WIDTH; ft++) {\r
-                if (board[0][ft] == WhiteRook) {\r
-                   callback(board, flags, \r
-                            (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR,\r
-                            0, ff, 0, ft, closure);\r
-                }\r
-             }\r
-          }\r
-       }\r
 \r
+    if ((flags & F_WHITE_ON_MOVE) != 0) {\r
+        ff = castlingRights[2]; /* King file if we have any rights */\r
+        if(ff > 0 && board[0][ff] == WhiteKing) {\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n",\r
+                castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]);\r
+    }\r
+            ft = castlingRights[0]; /* Rook file if we have H-side rights */\r
+            left  = ff+1;\r
+            right = BOARD_RGHT-2;\r
+            if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */\r
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
+                if(k != ft && board[0][k] != EmptySquare) ft = -1;\r
+            for(k=left; k<right && ft >= 0; k++) /* then if not checked */\r
+                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;\r
+            if(ft >= 0 && board[0][ft] == WhiteRook)\r
+                callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);\r
+\r
+            ft = castlingRights[1]; /* Rook file if we have A-side rights */\r
+            left  = BOARD_LEFT+2;\r
+            right = ff-1;\r
+            if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }\r
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
+                if(k != ft && board[0][k] != EmptySquare) ft = -1;\r
+            if(ff > BOARD_LEFT+2) \r
+            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */\r
+                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;\r
+            if(ft >= 0 && board[0][ft] == WhiteRook)\r
+                callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);\r
+        }\r
     } else {\r
-\r
-       for (ff = 1; ff < BOARD_WIDTH-1; ff++) {\r
-          if (board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
-             for (ft = 0; ft < BOARD_WIDTH; ft++) {\r
-                if (board[BOARD_HEIGHT-1][ft] == BlackRook) {\r
-                   callback(board, flags, \r
-                            (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR,\r
-                            BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
-                }\r
-             }\r
-          }\r
-       }\r
+        ff = castlingRights[5]; /* King file if we have any rights */\r
+        if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
+            ft = castlingRights[3]; /* Rook file if we have H-side rights */\r
+            left  = ff+1;\r
+            right = BOARD_RGHT-2;\r
+            if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */\r
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
+                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;\r
+            for(k=left; k<right && ft >= 0; k++) /* then if not checked */\r
+                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;\r
+            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)\r
+                callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
+\r
+            ft = castlingRights[4]; /* Rook file if we have A-side rights */\r
+            left  = BOARD_LEFT+2;\r
+            right = ff-1;\r
+            if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }\r
+            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */\r
+                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;\r
+            if(ff > BOARD_LEFT+2) \r
+            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */\r
+                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;\r
+            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)\r
+                callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
+        }\r
     }\r
 \r
-    /* POP Fabien */\r
+  }\r
 \r
     return FALSE;\r
 }\r
@@ -805,6 +961,11 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
     ChessSquare captured = EmptySquare;\r
     /*  Suppress warnings on uninitialized variables    */\r
 \r
+    if(gameInfo.variant == VariantXiangqi)\r
+        king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;\r
+    if(gameInfo.variant == VariantKnightmate)\r
+        king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;\r
+\r
     if (rf >= 0) {\r
        if (enPassant) {\r
            captured = board[rf][ft];\r
@@ -820,9 +981,20 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,\r
        and we test only whether that one is in check. */\r
     cl.check = 0;\r
-    for (cl.fking = 0; cl.fking < BOARD_WIDTH; cl.fking++)\r
+    for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)\r
        for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {\r
-         if (board[cl.rking][cl.fking] == king) {\r
+          if (board[cl.rking][cl.fking] == king) {\r
+              if(gameInfo.variant == VariantXiangqi) {\r
+                  /* [HGM] In Xiangqi opposing Kings means check as well */\r
+                  int i, dir;\r
+                  dir = (king >= BlackPawn) ? -1 : 1;\r
+                  for( i=cl.rking+dir; i>=0 && i<BOARD_HEIGHT &&\r
+                                board[i][cl.fking] == EmptySquare; i+=dir );\r
+                  if(i>=0 && i<BOARD_HEIGHT &&\r
+                      board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )\r
+                          cl.check++;\r
+              }\r
+\r
              GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,\r
                             CheckTestCallback, (VOIDSTAR) &cl);\r
              goto undo_move;  /* 2-level break */\r
@@ -858,6 +1030,9 @@ void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
 {\r
     register LegalityTestClosure *cl = (LegalityTestClosure *) closure;\r
 \r
+//    if (appData.debugMode) {\r
+//        fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);\r
+//    }\r
     if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)\r
       cl->kind = kind;\r
 }\r
@@ -868,14 +1043,61 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro
      int rf, ff, rt, ft, promoChar;\r
      char castlingRights[];\r
 {\r
-    LegalityTestClosure cl;\r
+    LegalityTestClosure cl; ChessSquare piece = board[rf][ff];\r
     \r
+    if (appData.debugMode) {\r
+        int i;\r
+        for(i=0; i<6; i++) fprintf(debugFP, "%d ", castlingRights[i]);\r
+        fprintf(debugFP, "Legality test? %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);\r
+    }\r
+    /* [HGM] Lance, Cobra and Falcon are wildcard pieces; consider all their moves legal */\r
+    /* (perhaps we should disallow moves that obviously leave us in check?)              */\r
+    if(piece == WhiteFalcon || piece == BlackFalcon ||\r
+       piece == WhiteCobra  || piece == BlackCobra  ||\r
+       piece == WhiteLance  || piece == BlackLance)\r
+        return NormalMove;\r
+\r
     cl.rf = rf;\r
     cl.ff = ff;\r
     cl.rt = rt;\r
     cl.ft = ft;\r
     cl.kind = IllegalMove;\r
     GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);\r
+\r
+    if(gameInfo.variant == VariantShogi) {\r
+        /* [HGM] Shogi promotions. '=' means defer */\r
+        if(rf != DROP_RANK && cl.kind == NormalMove) {\r
+            ChessSquare piece = board[rf][ff];\r
+\r
+            if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */\r
+            if(promoChar != NULLCHAR && promoChar != 'x' &&\r
+               promoChar != '+' && promoChar != '=' &&\r
+               ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )\r
+                    cl.kind = IllegalMove;\r
+            else if(flags & F_WHITE_ON_MOVE) {\r
+                if( (int) piece < (int) WhiteWazir &&\r
+                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
+                    if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
+                         piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
+                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
+                    else /* promotion optional, default is promote */\r
+                             cl.kind = promoChar == '=' ? NormalMove  : WhitePromotionQueen;\r
+                   \r
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+                                            NormalMove : IllegalMove;\r
+            } else {\r
+                if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
+                    if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
+                         piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
+                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
+                    else /* promotion optional, default is promote */\r
+                             cl.kind = promoChar == '=' ? NormalMove  : BlackPromotionQueen;\r
+\r
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+                                            NormalMove : IllegalMove;\r
+            }\r
+        }\r
+    } else\r
     if (promoChar != NULLCHAR && promoChar != 'x') {\r
        if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
            cl.kind = \r
@@ -884,6 +1106,7 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro
            cl.kind = IllegalMove;\r
        }\r
     }\r
+    /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */\r
     return cl.kind;\r
 }\r
 \r
@@ -921,7 +1144,8 @@ int MateTest(board, flags, epfile, castlingRights)
     if (cl.count > 0) {\r
        return inCheck ? MT_CHECK : MT_NONE;\r
     } else {\r
-       return inCheck ? MT_CHECKMATE : MT_STALEMATE;\r
+        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?\r
+                         MT_CHECKMATE : MT_STALEMATE;\r
     }\r
 }\r
 \r
@@ -939,14 +1163,17 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
 {\r
     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;\r
 \r
-    if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&\r
+    if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]\r
+         || PieceToChar(board[rf][ff]) == '~'\r
+              && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff])\r
+                                                                      ) &&\r
        (cl->rfIn == -1 || cl->rfIn == rf) &&\r
        (cl->ffIn == -1 || cl->ffIn == ff) &&\r
        (cl->rtIn == -1 || cl->rtIn == rt) &&\r
        (cl->ftIn == -1 || cl->ftIn == ft)) {\r
 \r
        cl->count++;\r
-       cl->piece = board[rf][ff];\r
+        cl->piece = board[rf][ff];\r
        cl->rf = rf;\r
        cl->ff = ff;\r
        cl->rt = rt;\r
@@ -960,10 +1187,15 @@ void Disambiguate(board, flags, epfile, closure)
      int flags, epfile;\r
      DisambiguateClosure *closure;\r
 {\r
-    int illegal = 0;\r
+    int illegal = 0; char c = closure->promoCharIn;\r
     closure->count = 0;\r
     closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
     closure->kind = ImpossibleMove;\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Disambiguate in:  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+                             closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
+                             closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');\r
+    }\r
     GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);\r
     if (closure->count == 0) {\r
        /* See if it's an illegal move due to check */\r
@@ -972,9 +1204,62 @@ void Disambiguate(board, flags, epfile, closure)
                 (VOIDSTAR) closure);   \r
        if (closure->count == 0) {\r
            /* No, it's not even that */\r
+    if (appData.debugMode) { int i, j;\r
+       for(i=BOARD_HEIGHT-1; i>=0; i--) {\r
+               for(j=0; j<BOARD_WIDTH; j++)\r
+                       fprintf(debugFP, "%3d", (int) board[i][j]);\r
+               fprintf(debugFP, "\n");\r
+       }\r
+    }\r
            return;\r
        }\r
     }\r
+\r
+    if(gameInfo.variant == VariantShogi) {\r
+        /* [HGM] Shogi promotions. '=' means defer */\r
+        if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {\r
+            ChessSquare piece = closure->piece;\r
+#if 0\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Disambiguate A:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
+                          closure->promoCharIn,closure->promoCharIn);\r
+    }\r
+#endif\r
+            if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&\r
+               ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) \r
+                    closure->kind = IllegalMove;\r
+            else if(flags & F_WHITE_ON_MOVE) {\r
+#if 0\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Disambiguate B:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
+                          closure->promoCharIn,closure->promoCharIn);\r
+    }\r
+#endif\r
+                if( (int) piece < (int) WhiteWazir &&\r
+                     (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {\r
+                    if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||\r
+                         piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
+                             closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;\r
+                    else /* promotion optional, default is promote */\r
+                             closure->kind = c == '=' ? NormalMove  : WhitePromotionQueen;\r
+                   \r
+                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
+                                            NormalMove : IllegalMove;\r
+            } else {\r
+                if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {\r
+                    if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||\r
+                         piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */\r
+                             closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;\r
+                    else /* promotion optional, default is promote */\r
+                             closure->kind = c == '=' ? NormalMove  : BlackPromotionQueen;\r
+\r
+                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?\r
+                                            NormalMove : IllegalMove;\r
+            }\r
+        }\r
+    } else\r
     if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {\r
        if (closure->kind == WhitePromotionQueen\r
            || closure->kind == BlackPromotionQueen) {\r
@@ -985,7 +1270,17 @@ void Disambiguate(board, flags, epfile, closure)
            closure->kind = IllegalMove;\r
        }\r
     }\r
-    closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
+#if 0\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Disambiguate C:   %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,\r
+                          closure->promoCharIn,closure->promoCharIn);\r
+    }\r
+#endif\r
+    /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */\r
+    if(closure->promoCharIn != '=')\r
+        closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
+    else closure->promoChar = '=';\r
     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
     if (closure->count > 1) {\r
        closure->kind = AmbiguousMove;\r
@@ -997,6 +1292,14 @@ void Disambiguate(board, flags, epfile, closure)
        */\r
        closure->kind = IllegalMove;\r
     }\r
+    if(closure->kind == IllegalMove)\r
+    /* [HGM] might be a variant we don't understand, pass on promotion info */\r
+        closure->promoChar = closure->promoCharIn;\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
+        closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,\r
+       closure->promoChar >= ' ' ? closure->promoChar:'-');\r
+    }\r
 }\r
 \r
 \r
@@ -1026,7 +1329,10 @@ void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
       (CoordsToAlgebraicClosure *) closure;\r
 \r
     if (rt == cl->rt && ft == cl->ft &&\r
-       board[rf][ff] == cl->piece) {\r
+        (board[rf][ff] == cl->piece\r
+         || PieceToChar(board[rf][ff]) == '~' &&\r
+            (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece)\r
+                                     ) {\r
        if (rf == cl->rf) {\r
            if (ff == cl->ff) {\r
                cl->kind = kind; /* this is the move we want */\r
@@ -1056,14 +1362,14 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
 {\r
     ChessSquare piece;\r
     ChessMove kind;\r
-    char *outp = out;\r
+    char *outp = out, c;\r
     CoordsToAlgebraicClosure cl;\r
     \r
     if (rf == DROP_RANK) {\r
        /* Bughouse piece drop */\r
        *outp++ = ToUpper(PieceToChar((ChessSquare) ff));\r
        *outp++ = '@';\r
-       *outp++ = ft + 'a';\r
+        *outp++ = ft + AAA;\r
         if(rt+ONE <= '9')\r
            *outp++ = rt + ONE;\r
         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
@@ -1073,6 +1379,10 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
 \r
     if (promoChar == 'x') promoChar = NULLCHAR;\r
     piece = board[rf][ff];\r
+    if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece);\r
+\r
+  if (appData.debugMode)\r
+          fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar >= ' ' ? promoChar : '-');\r
     switch (piece) {\r
       case WhitePawn:\r
       case BlackPawn:\r
@@ -1086,7 +1396,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
            kind = IllegalMove;\r
        }\r
        /* Pawn move */\r
-       *outp++ = ff + 'a';\r
+        *outp++ = ff + AAA;\r
         if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */\r
            /* Non-capture; use style "e5" */\r
             if(rt+ONE <= '9')\r
@@ -1096,18 +1406,26 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
            /* Capture; use style "exd5" */\r
             if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )\r
             *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */\r
-           *outp++ = ft + 'a';\r
+            *outp++ = ft + AAA;\r
             if(rt+ONE <= '9')\r
                *outp++ = rt + ONE;\r
             else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
        }\r
        /* Use promotion suffix style "=Q" */\r
-       if (promoChar != NULLCHAR && promoChar != 'x') {\r
-           *outp++ = '=';\r
-           *outp++ = ToUpper(promoChar);\r
-       }\r
        *outp = NULLCHAR;\r
-       return kind;\r
+  if (appData.debugMode)\r
+          fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar >= ' ' ? promoChar : '-');\r
+        if (promoChar != NULLCHAR) {\r
+            if(gameInfo.variant == VariantShogi) {\r
+                /* [HGM] ... but not in Shogi! */\r
+                *outp++ = promoChar == '=' ? '=' : '+';\r
+            } else {\r
+                *outp++ = '=';\r
+                *outp++ = ToUpper(promoChar);\r
+            }\r
+            *outp = NULLCHAR;\r
+       }\r
+        return kind;\r
 \r
        \r
       case WhiteKing:\r
@@ -1125,9 +1443,9 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
        /* Use style "O-O" (oh-oh) for PGN compatibility */\r
        else if (rf == rt &&\r
            rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&\r
-           ((ff == BOARD_WIDTH>>1 && (ft == 2 || ft == BOARD_WIDTH-2)) ||\r
-            (ff == (BOARD_WIDTH-1)>>1 && (ft == 1 || ft == BOARD_WIDTH-3)))) {\r
-           if(ft==1 || ft==BOARD_WIDTH-2)\r
+            ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||\r
+             (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {\r
+            if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)\r
                strcpy(out, "O-O");\r
             else\r
                strcpy(out, "O-O-O");\r
@@ -1172,10 +1490,16 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
           else "N1f3" or "N5xf7",\r
           else "Ng1f3" or "Ng5xf7".\r
        */\r
-       *outp++ = ToUpper(PieceToChar(piece));\r
-       \r
+        c = PieceToChar(piece) ;\r
+        if( c == '~' || c == '+') {\r
+           /* [HGM] print nonexistent piece as its demoted version */\r
+           piece = (ChessSquare) (DEMOTED piece);\r
+        }\r
+        if(c=='+') *outp++ = c;\r
+        *outp++ = ToUpper(PieceToChar(piece));\r
+\r
        if (cl.file || (cl.either && !cl.rank)) {\r
-           *outp++ = ff + 'a';\r
+            *outp++ = ff + AAA;\r
        }\r
        if (cl.rank) {\r
             if(rf+ONE <= '9')\r
@@ -1186,22 +1510,59 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
        if(board[rt][ft] != EmptySquare)\r
          *outp++ = 'x';\r
 \r
-       *outp++ = ft + 'a';\r
+        *outp++ = ft + AAA;\r
         if(rt+ONE <= '9')\r
            *outp++ = rt + ONE;\r
         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
        *outp = NULLCHAR;\r
-       return cl.kind;\r
+        if (gameInfo.variant == VariantShogi) {\r
+            /* [HGM] in Shogi non-pawns can promote */\r
+            if(flags & F_WHITE_ON_MOVE) {\r
+                if( (int) cl.piece < (int) WhiteWazir &&\r
+                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {\r
+                    if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||\r
+                         piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */\r
+                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;\r
+                    else cl.kind =  WhitePromotionQueen; /* promotion optional */\r
+                   \r
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+                                            NormalMove : IllegalMove;\r
+            } else {\r
+                if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {\r
+                    if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||\r
+                         piece == BlackKnight && rt < 2 ) /* promotion obligatory */\r
+                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;\r
+                    else cl.kind =  BlackPromotionQueen; /* promotion optional */\r
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?\r
+                                            NormalMove : IllegalMove;\r
+            }\r
+            if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
+                /* for optional promotions append '+' or '=' */\r
+                if(promoChar == '=') {\r
+                    *outp++ = '=';\r
+                    cl.kind = NormalMove;\r
+                } else *outp++ = '+';\r
+                *outp = NULLCHAR;\r
+            } else if(cl.kind == IllegalMove) {\r
+                /* Illegal move specifies any given promotion */\r
+                if(promoChar != NULLCHAR && promoChar != 'x') {\r
+                    *outp++ = '=';\r
+                    *outp++ = ToUpper(promoChar);\r
+                    *outp = NULLCHAR;\r
+                }\r
+            }\r
+        }\r
+        return cl.kind;\r
        \r
-#ifdef FAIRY\r
-      /* [HGM] Always long notation for fairies, don't know how they move */\r
-      case WhiteFairyRook:\r
-      case BlackFairyRook:\r
-      case WhiteFairyKnight:\r
-      case BlackFairyKnight:\r
-      case WhiteFairyQueen:\r
-      case BlackFairyQueen:\r
-#endif\r
+      /* [HGM] Always long notation for fairies we don't know */\r
+      case WhiteFalcon:\r
+      case BlackFalcon:\r
+      case WhiteSilver:\r
+      case BlackSilver:\r
+      case WhiteLance:\r
+      case BlackLance:\r
+      case WhiteGrasshopper:\r
+      case BlackGrasshopper:\r
       case EmptySquare:\r
        /* Moving a nonexistent piece */\r
        break;\r
@@ -1219,12 +1580,12 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
     if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {\r
        *outp++ = ToUpper(PieceToChar(piece));\r
     }\r
-    *outp++ = ff + 'a';\r
+    *outp++ = ff + AAA;\r
     if(rf+ONE <= '9')\r
        *outp++ = rf + ONE;\r
     else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
     if (board[rt][ft] != EmptySquare) *outp++ = 'x';\r
-    *outp++ = ft + 'a';\r
+    *outp++ = ft + AAA;\r
     if(rt+ONE <= '9')\r
        *outp++ = rt + ONE;\r
     else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r