use autoheader to create config.h.in
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 9aff915..58cbfc0 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -117,91 +117,27 @@ 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', 'F', \r
-    'W', 'E', 'M', 'O', 'U', 'H', 'A', 'C', 'G', 'S',\r
-    'K',                'p', 'n', 'b', 'r', 'q', 'f', \r
-    'w', 'e', 'm', 'o', 'u', 'h', 'a', 'c', 'g', 's',\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
@@ -210,7 +146,7 @@ char PieceToChar(p)
     return pieceToChar[(int) p];\r
 }\r
 \r
-int PieceToNumber(p)\r
+int PieceToNumber(p)  /* [HGM] holdings: count piece type, ignoring non-participating piece types */\r
      ChessSquare p;\r
 {\r
     int i=0;\r
@@ -229,6 +165,52 @@ ChessSquare CharToPiece(c)
      return EmptySquare;\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) );
+       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
      Board to, from;\r
 {\r
@@ -281,9 +263,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
@@ -294,7 +274,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              /* can't happen ([HGM] except for faries...) */\r
              break;\r
 \r
-           case WhitePawn:\r
+             case WhitePawn:\r
               if(gameInfo.variant == VariantXiangqi) {\r
                   /* [HGM] capture and move straight ahead in Xiangqi */\r
                   if (rf < BOARD_HEIGHT-1 &&\r
@@ -521,8 +501,8 @@ 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
@@ -572,8 +552,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
@@ -598,7 +578,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
@@ -645,7 +625,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
@@ -653,6 +633,9 @@ 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
@@ -670,7 +653,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
@@ -738,8 +740,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
@@ -749,10 +752,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
@@ -763,15 +770,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==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
-                     0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2), closure);\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
@@ -781,7 +789,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
@@ -790,7 +798,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
@@ -801,15 +809,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
@@ -819,8 +828,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
@@ -828,41 +837,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
+    /* [HGM] test if the Rooks we find have castling rights */\r
 \r
-    if ((flags & F_WHITE_ON_MOVE) != 0) {\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
@@ -932,6 +971,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
@@ -967,9 +1017,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
@@ -980,8 +1030,20 @@ 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
@@ -1069,7 +1131,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
@@ -1088,7 +1150,10 @@ 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
@@ -1113,6 +1178,11 @@ void Disambiguate(board, flags, epfile, closure)
     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
@@ -1121,31 +1191,39 @@ 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 (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,closure->promoCharIn,closure->promoCharIn);\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
-\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,closure->promoCharIn,closure->promoCharIn);\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,closure->promoCharIn,closure->promoCharIn);\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
@@ -1179,13 +1257,16 @@ void Disambiguate(board, flags, epfile, closure)
            closure->kind = IllegalMove;\r
        }\r
     }\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,closure->promoCharIn,closure->promoCharIn);\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
+        closure->promoChar = ToLower(closure->promoCharIn);\r
     else closure->promoChar = '=';\r
     if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
     if (closure->count > 1) {\r
@@ -1200,10 +1281,11 @@ void Disambiguate(board, flags, epfile, closure)
     }\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
+        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,closure->promoChar);\r
+        closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,\r
+       closure->promoChar >= ' ' ? closure->promoChar:'-');\r
     }\r
 }\r
 \r
@@ -1234,7 +1316,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
@@ -1264,7 +1349,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
@@ -1276,20 +1361,18 @@ 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\n", (int)piece);\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
-  if (appData.debugMode)\r
-          fprintf(debugFP, "CoordsToAlgebraic, Pawn\n");\r
         kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);\r
        if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
            /* Keep short notation if move is illegal only because it\r
@@ -1317,6 +1400,8 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
        }\r
        /* Use promotion suffix style "=Q" */\r
        *outp = NULLCHAR;\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
@@ -1327,7 +1412,6 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
             }\r
             *outp = NULLCHAR;\r
        }\r
-        AlphaRank(out, 10);\r
         return kind;\r
 \r
        \r
@@ -1393,13 +1477,14 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
           else "N1f3" or "N5xf7",\r
           else "Ng1f3" or "Ng5xf7".\r
        */\r
-        if(PieceToChar(piece) == '.') {\r
+        c = PieceToChar(piece) ;\r
+        if( c == '~' || c == '+') {\r
            /* [HGM] print nonexistent piece as its demoted version */\r
            piece = (ChessSquare) (DEMOTED piece);\r
-           if( gameInfo.variant == VariantShogi )\r
-                *outp++ = '+';\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
@@ -1454,12 +1539,13 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
                 }\r
             }\r
         }\r
-        AlphaRank(out, 10);\r
         return cl.kind;\r
        \r
       /* [HGM] Always long notation for fairies we don't know */\r
-      case WhiteNightrider:\r
-      case BlackNightrider:\r
+      case WhiteFalcon:\r
+      case BlackFalcon:\r
+      case WhiteLance:\r
+      case BlackLance:\r
       case WhiteGrasshopper:\r
       case BlackGrasshopper:\r
       case EmptySquare:\r
@@ -1495,7 +1581,6 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
     }\r
     *outp = NULLCHAR;\r
 \r
-    AlphaRank(out, 0);\r
     return IllegalMove;\r
 }\r
 \r