changes from H.G. Muller; version 4.3.7
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 2070ef3..9aff915 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -196,23 +196,30 @@ ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
 }\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
+                        '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
 \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)\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 +227,6 @@ 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
 void CopyBoard(to, from)\r
@@ -330,7 +295,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
              break;\r
 \r
            case WhitePawn:\r
-#ifdef FAIRY\r
               if(gameInfo.variant == VariantXiangqi) {\r
                   /* [HGM] capture and move straight ahead in Xiangqi */\r
                   if (rf < BOARD_HEIGHT-1 &&\r
@@ -349,7 +313,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 +346,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 +363,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 +395,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 +413,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 +427,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 +464,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 +478,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
@@ -574,7 +528,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
             /* 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 +546,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
@@ -632,7 +584,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
@@ -667,7 +618,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
@@ -707,7 +657,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
             case BlackMan:\r
             case SHOGI WhiteKing:\r
             case SHOGI BlackKing:\r
-#endif\r
            case WhiteKing:\r
            case BlackKing:\r
             walking:\r
@@ -817,7 +766,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
              !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
 \r
            callback(board, flags,\r
-                    ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
+                     ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
                      0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2), closure);\r
        }\r
        if ((flags & F_WHITE_ON_MOVE) &&\r
@@ -1039,6 +988,41 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro
     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
@@ -1047,6 +1031,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
@@ -1110,7 +1095,7 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
        (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,7 +1109,7 @@ 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
@@ -1139,6 +1124,51 @@ void Disambiguate(board, flags, epfile, closure)
            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 (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
+    }\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 (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
+    }\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 +1179,14 @@ void Disambiguate(board, flags, epfile, closure)
            closure->kind = IllegalMove;\r
        }\r
     }\r
-    closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\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
+    }\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
@@ -1161,6 +1198,13 @@ 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,closure->promoChar);\r
+    }\r
 }\r
 \r
 \r
@@ -1238,9 +1282,14 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
 \r
     if (promoChar == 'x') promoChar = NULLCHAR;\r
     piece = board[rf][ff];\r
+\r
+  if (appData.debugMode)\r
+          fprintf(debugFP, "CoordsToAlgebraic, piece=%d\n", (int)piece);\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
@@ -1267,11 +1316,17 @@ 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
+        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
         AlphaRank(out, 10);\r
         return kind;\r
 \r
@@ -1338,8 +1393,13 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
           else "N1f3" or "N5xf7",\r
           else "Ng1f3" or "Ng5xf7".\r
        */\r
-       *outp++ = ToUpper(PieceToChar(piece));\r
-       \r
+        if(PieceToChar(piece) == '.') {\r
+           /* [HGM] print nonexistent piece as its demoted version */\r
+           piece = (ChessSquare) (DEMOTED piece);\r
+           if( gameInfo.variant == VariantShogi )\r
+                *outp++ = '+';\r
+        }\r
+        *outp++ = ToUpper(PieceToChar(piece));\r
        if (cl.file || (cl.either && !cl.rank)) {\r
             *outp++ = ff + AAA;\r
        }\r
@@ -1357,16 +1417,51 @@ 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
+        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
         AlphaRank(out, 10);\r
         return cl.kind;\r
        \r
-#ifdef FAIRY\r
-      /* [HGM] Always long notation for fairies, don't know how they move */\r
+      /* [HGM] Always long notation for fairies we don't know */\r
       case WhiteNightrider:\r
       case BlackNightrider:\r
       case WhiteGrasshopper:\r
       case BlackGrasshopper:\r
-#endif\r
       case EmptySquare:\r
        /* Moving a nonexistent piece */\r
        break;\r