updated INSTALL, NEWS and other files for new release
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 2070ef3..eb0701c 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -117,102 +117,45 @@ ChessSquare PromoPiece(moveType)
        return WhiteKing;\r
       case BlackPromotionKing:\r
        return BlackKing;\r
-#ifdef FAIRY\r
       case WhitePromotionChancellor:\r
         return WhiteMarshall;\r
       case BlackPromotionChancellor:\r
         return BlackMarshall;\r
       case WhitePromotionArchbishop:\r
-        return WhiteCardinal;\r
+        return WhiteAngel;\r
       case BlackPromotionArchbishop:\r
-        return BlackCardinal;\r
-#endif\r
-    }\r
-}\r
-\r
-ChessMove PromoCharToMoveType(whiteOnMove, promoChar)\r
-     int whiteOnMove;\r
-     int promoChar;\r
-{\r
-    if (whiteOnMove) {\r
-       switch (promoChar) {\r
-         case 'n':\r
-         case 'N':\r
-           return WhitePromotionKnight;\r
-         case 'b':\r
-         case 'B':\r
-           return WhitePromotionBishop;\r
-         case 'r':\r
-         case 'R':\r
-           return WhitePromotionRook;\r
-#ifdef FAIRY\r
-          case 'a':\r
-          case 'A':\r
-            return WhitePromotionArchbishop;\r
-          case 'c':\r
-          case 'C':\r
-            return WhitePromotionChancellor;\r
-#endif\r
-         case 'q':\r
-         case 'Q':\r
-           return WhitePromotionQueen;\r
-         case 'k':\r
-         case 'K':\r
-           return WhitePromotionKing;\r
-         case NULLCHAR:\r
-         default:\r
-           return NormalMove;\r
-       }\r
-    } else {\r
-       switch (promoChar) {\r
-         case 'n':\r
-         case 'N':\r
-           return BlackPromotionKnight;\r
-         case 'b':\r
-         case 'B':\r
-           return BlackPromotionBishop;\r
-         case 'r':\r
-         case 'R':\r
-           return BlackPromotionRook;\r
-#ifdef FAIRY\r
-          case 'a':\r
-          case 'A':\r
-            return BlackPromotionArchbishop;\r
-          case 'c':\r
-          case 'C':\r
-            return BlackPromotionChancellor;\r
-#endif\r
-         case 'q':\r
-         case 'Q':\r
-           return BlackPromotionQueen;\r
-         case 'k':\r
-         case 'K':\r
-           return BlackPromotionKing;\r
-         case NULLCHAR:\r
-         default:\r
-           return NormalMove;\r
-       }\r
+        return BlackAngel;\r
+      case WhitePromotionCentaur:\r
+        return WhiteSilver;\r
+      case BlackPromotionCentaur:\r
+        return BlackSilver;\r
     }\r
 }\r
 \r
 char pieceToChar[] = {\r
-              'P', 'N', 'B', 'R', 'Q', \r
-#ifdef FAIRY\r
-    'F', 'W', 'E', 'H', 'A', 'C', 'G', 'O', 'M', 'U', \r
-#endif\r
-    'K',      'p', 'n', 'b', 'r', 'q', \r
-#ifdef FAIRY            \r
-    'f', 'w', 'e', 'h', 'a', 'c', 'g', 'o', 'm', 'u',\r
-#endif\r
-    'k', 'x'\r
-  };\r
+                        'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', \r
+                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',\r
+                        'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', \r
+                        'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', '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
 {\r
@@ -220,48 +163,54 @@ ChessSquare CharToPiece(c)
      for(i=0; i< (int) EmptySquare; i++)\r
           if(pieceToChar[i] == c) return (ChessSquare) i;\r
      return EmptySquare;\r
-/* [HGM] code marked for deletion\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 WhiteFerz;\r
-      case 'H': return WhiteNightrider;\r
-      case 'E': return WhiteAlfil;\r
-      case 'W': return WhiteWazir;\r
-      case 'U': return WhiteUnicorn;\r
-      case 'O': return WhiteCannon;\r
-      case 'G': return WhiteGrasshopper;\r
-      case 'M': return WhiteMan;\r
-                \r
-      case 'a': return BlackCardinal;\r
-      case 'c': return BlackMarshall;\r
-      case 'f': return BlackFerz;\r
-      case 'h': return BlackNightrider;\r
-      case 'e': return BlackAlfil;\r
-      case 'w': return BlackWazir;\r
-      case 'u': return BlackUnicorn;\r
-      case 'o': return BlackCannon;\r
-      case 'g': return BlackGrasshopper;\r
-      case 'm': return BlackMan;\r
-                \r
-#endif\r
-    }\r
-*/\r
+}\r
+\r
+ChessMove PromoCharToMoveType(whiteOnMove, promoChar)\r
+     int whiteOnMove;\r
+     int promoChar;\r
+{      /* [HGM] made dependent on CharToPiece to alow alternate piece letters */\r
+       ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) );\r
+\r
+
+       if(promoChar == NULLCHAR) return NormalMove;\r
+\r
+       switch(piece) {\r
+               case WhiteQueen:\r
+                       return WhitePromotionQueen;\r
+               case WhiteRook:\r
+                       return WhitePromotionRook;\r
+               case WhiteBishop:\r
+                       return WhitePromotionBishop;\r
+               case WhiteKnight:\r
+                       return WhitePromotionKnight;\r
+               case WhiteKing:\r
+                       return WhitePromotionKing;\r
+               case WhiteAngel:\r
+                       return WhitePromotionArchbishop;\r
+               case WhiteMarshall:\r
+                       return WhitePromotionChancellor;\r
+               case WhiteSilver:\r
+                       return WhitePromotionCentaur;\r
+               case BlackQueen:\r
+                       return BlackPromotionQueen;\r
+               case BlackRook:\r
+                       return BlackPromotionRook;\r
+               case BlackBishop:\r
+                       return BlackPromotionBishop;\r
+               case BlackKnight:\r
+                       return BlackPromotionKnight;\r
+               case BlackKing:\r
+                       return BlackPromotionKing;\r
+               case BlackAngel:\r
+                       return BlackPromotionArchbishop;\r
+               case BlackMarshall:\r
+                       return BlackPromotionChancellor;\r
+               case BlackSilver:\r
+                       return BlackPromotionCentaur;\r
+               default:\r
+                       // not all promotion implemented yet! Take Queen for those we don't know.\r
+                       return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen);\r
+       }\r
 }\r
 \r
 void CopyBoard(to, from)\r
@@ -316,9 +265,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              if (!BlackPiece(board[rf][ff])) continue;\r
          }\r
           m = 0; piece = board[rf][ff];\r
-          if(gameInfo.variant == VariantCrazyhouse &&\r
-              ( (int) piece > (int) WhiteQueen && (int) piece < (int) WhiteKing\r
-             || (int) piece > (int) BlackQueen && (int) piece < (int) BlackKing ))\r
+          if(PieceToChar(piece) == '~') \r
                  piece = (ChessSquare) ( DEMOTED piece );\r
           if(gameInfo.variant == VariantShogi)\r
                  piece = (ChessSquare) ( SHOGI piece );\r
@@ -329,8 +276,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              /* 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
@@ -349,7 +295,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
@@ -383,7 +328,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
@@ -401,7 +345,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
@@ -434,10 +377,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              }             \r
              break;\r
 \r
-#ifdef FAIRY\r
             case WhiteUnicorn:\r
             case BlackUnicorn:\r
-#endif\r
            case WhiteKnight:\r
            case BlackKnight:\r
             mounted:\r
@@ -454,13 +395,11 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                  }\r
              break;\r
 \r
-#ifdef FAIRY\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, \r
-                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
+                      callback(board, flags, NormalMove,\r
                                rf, ff, rf + 2, ff + s, closure);\r
                  }\r
               }\r
@@ -470,8 +409,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              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, \r
-                              rf == 1 ? BlackPromotionQueen : NormalMove,\r
+                      callback(board, flags, NormalMove,\r
                                rf, ff, rf - 2, ff + s, closure);\r
                  }\r
              }             \r
@@ -508,8 +446,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              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, \r
-                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
+                      callback(board, flags, NormalMove,\r
                               rf, ff, rf + 1, ff + s, closure);\r
                  }\r
               }\r
@@ -523,8 +460,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              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, \r
-                              rf == 1 ? BlackPromotionQueen : NormalMove,\r
+                      callback(board, flags, NormalMove,\r
                               rf, ff, rf - 1, ff + s, closure);\r
                  }\r
              }             \r
@@ -567,14 +503,13 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               m++;\r
 \r
             /* Capablanca Archbishop continues as Knight                  */\r
-            case WhiteCardinal:\r
-            case BlackCardinal:\r
+            case WhiteAngel:\r
+            case BlackAngel:\r
               m++;\r
 \r
             /* Shogi Bishops are ordinary Bishops */\r
             case SHOGI WhiteBishop:\r
             case SHOGI BlackBishop:\r
-#endif\r
            case WhiteBishop:\r
            case BlackBishop:\r
              for (rs = -1; rs <= 1; rs += 2) \r
@@ -593,7 +528,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                 /* 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
@@ -620,8 +554,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               break;\r
 \r
             /* Shogi Dragon King has to continue as Ferz after Rook moves */\r
-            case SHOGI WhiteMarshall:\r
-            case SHOGI BlackMarshall:\r
+            case SHOGI WhiteDragon:\r
+            case SHOGI BlackDragon:\r
               m++;\r
 \r
             /* Capablanca Chancellor sets flag to continue as Knight      */\r
@@ -632,7 +566,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
             /* Shogi Rooks are ordinary Rooks */\r
             case SHOGI WhiteRook:\r
             case SHOGI BlackRook:\r
-#endif\r
            case WhiteRook:\r
            case BlackRook:\r
               for (d = 0; d <= 1; d++)\r
@@ -647,7 +580,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      if (board[rt][ft] != EmptySquare) break;\r
                  }\r
                 if(m==1) goto mounted;\r
-                if(m==2) goto walking;\r
+                if(m==2) goto finishGold;\r
              break;\r
 \r
            case WhiteQueen:\r
@@ -667,7 +600,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                }\r
              break;\r
 \r
-#ifdef FAIRY\r
             /* Shogi Pawn and Silver General: first the Pawn move,    */\r
             /* then the General continues like a Ferz                 */\r
             case SHOGI WhitePawn:\r
@@ -695,7 +627,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                   for (fs = -1; fs <= 1; fs += 2) {\r
                       rt = rf + rs;\r
                       ft = ff + fs;\r
-                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break;\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
@@ -703,11 +635,13 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                  }\r
                 break;\r
 \r
+           case WhiteSilver:\r
+           case BlackSilver:\r
+               m++; // [HGM] superchess: use for Centaur\r
             case WhiteMan:\r
             case BlackMan:\r
             case SHOGI WhiteKing:\r
             case SHOGI BlackKing:\r
-#endif\r
            case WhiteKing:\r
            case BlackKing:\r
             walking:\r
@@ -721,7 +655,26 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                    callback(board, flags, NormalMove,\r
                             rf, ff, rt, ft, closure);\r
                }\r
+               if(m==1) goto mounted;\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
@@ -789,8 +742,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
@@ -800,10 +754,14 @@ 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] == wKing &&\r
             board[0][ff + 1] == EmptySquare &&\r
             board[0][ff + 2] == EmptySquare &&\r
             board[0][BOARD_RGHT-3] == EmptySquare &&\r
@@ -814,15 +772,16 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             (ignoreCheck ||                             \r
             (!CheckTest(board, flags, 0, ff, 0, ff + 1, 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 + ((gameInfo.boardWidth+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][BOARD_LEFT+2] == EmptySquare &&\r
@@ -832,7 +791,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             ( 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_LEFT+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
@@ -841,7 +800,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
        }\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_RGHT-3] == EmptySquare &&\r
@@ -852,15 +811,16 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
            (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_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 + ((gameInfo.boardWidth+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][BOARD_LEFT+2] == EmptySquare &&\r
@@ -870,8 +830,8 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             ( 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_LEFT+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
@@ -879,41 +839,71 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
        }\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
-\r
-    if ((flags & F_WHITE_ON_MOVE) != 0) {\r
+    /* [HGM] test if the Rooks we find have castling rights */\r
 \r
-       for (ff = BOARD_LEFT+1; ff < BOARD_RGHT-1; ff++) {\r
-          if (board[0][ff] == WhiteKing) {\r
-             for (ft = BOARD_LEFT+0; ft < BOARD_RGHT; 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 = BOARD_LEFT+1; ff < BOARD_RGHT-1; ff++) {\r
-          if (board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
-             for (ft = BOARD_LEFT+0; ft < BOARD_RGHT; 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
@@ -983,6 +973,17 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
     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(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
@@ -1018,9 +1019,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 (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
@@ -1031,15 +1032,63 @@ 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(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi\r
        if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
            cl.kind = \r
              PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);\r
@@ -1047,6 +1096,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
@@ -1084,7 +1134,7 @@ int MateTest(board, flags, epfile, castlingRights)
     if (cl.count > 0) {\r
        return inCheck ? MT_CHECK : MT_NONE;\r
     } else {\r
-        return inCheck || gameInfo.variant == VariantXiangqi ?\r
+        return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ?\r
                          MT_CHECKMATE : MT_STALEMATE;\r
     }\r
 }\r
@@ -1103,14 +1153,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
@@ -1124,10 +1177,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
@@ -1136,9 +1194,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
@@ -1149,7 +1260,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(closure->promoCharIn);\r
+    else closure->promoChar = '=';\r
     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
     if (closure->count > 1) {\r
        closure->kind = AmbiguousMove;\r
@@ -1161,6 +1282,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 = ToLower(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
@@ -1190,7 +1319,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
@@ -1220,7 +1352,7 @@ 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
@@ -1232,12 +1364,15 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
            *outp++ = rt + ONE;\r
         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
        *outp = NULLCHAR;\r
-        AlphaRank(out, 5);\r
        return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;\r
     }\r
 \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
@@ -1267,12 +1402,19 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
             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
-        AlphaRank(out, 10);\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
@@ -1338,8 +1480,14 @@ 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 + AAA;\r
        }\r
@@ -1357,16 +1505,52 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
            *outp++ = rt + ONE;\r
         else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
        *outp = NULLCHAR;\r
-        AlphaRank(out, 10);\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 WhiteNightrider:\r
-      case BlackNightrider:\r
+      /* [HGM] Always long notation for fairies we don't know */\r
+      case WhiteFalcon:\r
+      case BlackFalcon:\r
+      case WhiteLance:\r
+      case BlackLance:\r
       case WhiteGrasshopper:\r
       case BlackGrasshopper:\r
-#endif\r
       case EmptySquare:\r
        /* Moving a nonexistent piece */\r
        break;\r
@@ -1400,7 +1584,6 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
     }\r
     *outp = NULLCHAR;\r
 \r
-    AlphaRank(out, 0);\r
     return IllegalMove;\r
 }\r
 \r