changes from H.G. Muller; version 4.3.12
[xboard.git] / backend.c
index 79bdc68..e9e1368 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -1789,6 +1789,9 @@ VariantSwitch(Board board, VariantClass newVariant)
         gameInfo.holdingsWidth = newHoldingsWidth;\r
         gameInfo.variant = newVariant;\r
         InitDrawingSizes(-2, 0);\r
+\r
+        if(board != boards[0]) InitPosition(FALSE);\r
+\r
     } else gameInfo.variant = newVariant;\r
 }\r
 \r
@@ -3311,6 +3314,10 @@ ParseBoard12(string)
            fromX = fromY = toX = toY = -1;\r
        } else {\r
            /* Move from ICS was illegal!?  Punt. */\r
+  if (appData.debugMode) {\r
+    fprintf(debugFP, "Illegal move from ICS '%s'\n", move_str);\r
+    fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+  }\r
 #if 0\r
            if (appData.testLegality && appData.debugMode) {\r
                sprintf(str, "Illegal move \"%s\" from ICS", move_str);\r
@@ -3478,11 +3485,6 @@ SendMoveToProgram(moveNum, cps)
       } else {\r
        sprintf(buf, "%s\n", parseList[moveNum]);\r
       }\r
-      /* [HGM] decrement all digits to code ranks starting from 0 */\r
-      if(BOARD_HEIGHT>9) {\r
-          char *p = buf;\r
-          while(*p) { if(*p < 'A') (*p)--; p++; }\r
-      }\r
       SendToProgram(buf, cps);\r
     } else {\r
       /* Added by Tord: Send castle moves in "O-O" in FRC games if required by\r
@@ -3616,15 +3618,62 @@ ProcessICSInitScript(f)
 void\r
 AlphaRank(char *move, int n)\r
 {\r
-    char *p = move, c;\r
+    char *p = move, c; int x, y;\r
 \r
     if( !appData.alphaRank ) return;\r
 \r
-    while(c = *p) {\r
-        if(c>='0' && c<='9') *p += AAA-ONE; else\r
-        if(c>='a' && c<'x') *p -= AAA-ONE;\r
-        p++;\r
-        if(--n < 1) break;\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "alphaRank(%s,%d)\n", move, n);\r
+    }\r
+\r
+    if(move[1]=='*' && \r
+       move[2]>='0' && move[2]<='9' &&\r
+       move[3]>='a' && move[3]<='x'    ) {\r
+        move[2] = (move[2]-'1')+BOARD_LEFT + AAA;\r
+        move[3] = (move[3]-'a') + ONE;\r
+    } else\r
+    if(move[0]>='0' && move[0]<='9' &&\r
+       move[1]>='a' && move[1]<='x' &&\r
+       move[2]>='0' && move[2]<='9' &&\r
+       move[3]>='a' && move[3]<='x'    ) {\r
+        /* input move, Shogi -> normal */\r
+/*\r
+        move[0] = BOARD_RGHT  -1-(move[0]-'1') + AAA;\r
+        move[1] = BOARD_HEIGHT-1-(move[1]-'a') + ONE;\r
+        move[2] = BOARD_RGHT  -1-(move[2]-'1') + AAA;\r
+        move[3] = BOARD_HEIGHT-1-(move[3]-'a') + ONE;\r
+*/\r
+        move[0] = (move[0]-'1')+BOARD_LEFT + AAA;\r
+        move[1] = (move[1]-'a') + ONE;\r
+        move[2] = (move[2]-'1')+BOARD_LEFT + AAA;\r
+        move[3] = (move[3]-'a') + ONE;\r
+    } else\r
+    if(move[1]=='@' &&\r
+       move[3]>='0' && move[3]<='9' &&\r
+       move[2]>='a' && move[2]<='x'    ) {\r
+        move[1] = '*';\r
+        move[2] = (move[2]-AAA)-BOARD_LEFT + '1';\r
+        move[3] = (move[3]-ONE) + 'a';\r
+    } else\r
+    if(\r
+       move[0]>='a' && move[0]<='x' &&\r
+       move[3]>='0' && move[3]<='9' &&\r
+       move[2]>='a' && move[2]<='x'    ) {\r
+         /* output move, normal -> Shogi */\r
+/*\r
+        move[0] = BOARD_RGHT  -1-(move[0]-AAA) + '1';\r
+        move[1] = BOARD_HEIGHT-1-(move[1]-ONE) + 'a';\r
+        move[2] = BOARD_RGHT  -1-(move[2]-AAA) + '1';\r
+        move[3] = BOARD_HEIGHT-1-(move[3]-ONE) + 'a';\r
+*/\r
+        move[0] = (move[0]-AAA)-BOARD_LEFT + '1';\r
+        move[1] = (move[1]-ONE) + 'a';\r
+        move[2] = (move[2]-AAA)-BOARD_LEFT + '1';\r
+        move[3] = (move[3]-ONE) + 'a';\r
+        if(move[4] == PieceToChar(BlackQueen)) move[4] = '+';\r
+    }\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "   out = '%s'\n", move);\r
     }\r
 }\r
 \r
@@ -3640,16 +3689,13 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
     if (appData.debugMode) {\r
         fprintf(debugFP, "move to parse: %s\n", move);\r
     }\r
-    AlphaRank(move, 10);\r
     *moveType = yylexstr(moveNum, move);\r
 \r
     switch (*moveType) {\r
-#ifdef FAIRY\r
       case WhitePromotionChancellor:\r
       case BlackPromotionChancellor:\r
       case WhitePromotionArchbishop:\r
       case BlackPromotionArchbishop:\r
-#endif\r
       case WhitePromotionQueen:\r
       case BlackPromotionQueen:\r
       case WhitePromotionRook:\r
@@ -3685,6 +3731,9 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
        *promoChar = currentMoveString[4];\r
         if (*fromX < BOARD_LEFT || *fromX >= BOARD_RGHT || *fromY < 0 || *fromY >= BOARD_HEIGHT ||\r
             *toX < BOARD_LEFT || *toX >= BOARD_RGHT || *toY < 0 || *toY >= BOARD_HEIGHT) {\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Off-board move (%d,%d)-(%d,%d)%c, type = %d\n", *fromX, *fromY, *toX, *toY, *promoChar, *moveType);\r
+    }\r
            *fromX = *fromY = *toX = *toY = 0;\r
            return FALSE;\r
        }\r
@@ -3716,6 +3765,9 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
       case BlackWins:\r
       case GameIsDrawn:\r
       default:\r
+    if (appData.debugMode) {\r
+        fprintf(debugFP, "Impossible move %s, type = %d\n", currentMoveString, *moveType);\r
+    }\r
        /* bug? */\r
        *fromX = *fromY = *toX = *toY = 0;\r
        *promoChar = NULLCHAR;\r
@@ -3855,6 +3907,9 @@ InitPosition(redraw)
         }\r
 \r
         initialRulePlies = 0; /* 50-move counter start */\r
+\r
+        castlingRank[0] = castlingRank[1] = castlingRank[2] = 0;\r
+        castlingRank[3] = castlingRank[4] = castlingRank[5] = BOARD_HEIGHT-1;\r
     }\r
 \r
     \r
@@ -3887,7 +3942,7 @@ InitPosition(redraw)
       castlingRights[0][6] = initialRights[2] = 5;\r
       castlingRights[0][7] = initialRights[5] = 5;\r
       castlingRank[6] = 0;\r
-      castlingRank[6] = BOARD_HEIGHT-1;\r
+      castlingRank[7] = BOARD_HEIGHT-1;\r
       startedFromSetupPosition = TRUE;\r
       break;\r
     case VariantCapablanca:\r
@@ -3913,7 +3968,7 @@ InitPosition(redraw)
       gameInfo.boardHeight = 9;\r
       gameInfo.holdingsSize = 7;\r
       nrCastlingRights = 0;\r
-      SetCharTable(pieceToChar, "PNBRLSG.........Kpnbrlsg.........k"); \r
+      SetCharTable(pieceToChar, "PNBRLSG...++++++Kpnbrlsg...++++++k"); \r
       break;\r
     case VariantShowgi:\r
       pieces = ShogiArray;\r
@@ -3933,7 +3988,7 @@ InitPosition(redraw)
       break;\r
     case VariantKnightmate:\r
       pieces = KnightmateArray;\r
-      strcpy(pieceToChar, "P.BRQ...M.K......p.brq...m.k......"); \r
+      SetCharTable(pieceToChar, "P.BRQ...M.K......p.brq...m.k......"); \r
       break;\r
     case VariantFairy:\r
       pieces = fairyArray;\r
@@ -3943,6 +3998,7 @@ InitPosition(redraw)
     case VariantCrazyhouse:\r
     case VariantBughouse:\r
       pieces = FIDEArray;\r
+      SetCharTable(pieceToChar, "PNBRQ......~~~~.Kpnbrq......~~~~.k"); \r
       gameInfo.holdingsSize = 5;\r
       break;\r
     case VariantWildCastle:\r
@@ -4027,9 +4083,6 @@ InitPosition(redraw)
         castlingRights[0][3] = initialRights[3] = BOARD_RGHT-1;\r
         castlingRights[0][4] = initialRights[4] = BOARD_LEFT;\r
         castlingRights[0][5] = initialRights[5] = BOARD_WIDTH>>1;\r
-\r
-        castlingRank[0] = castlingRank[1] = castlingRank[2] = 0;\r
-        castlingRank[3] = castlingRank[4] = castlingRank[5] = BOARD_HEIGHT-1;\r
      }\r
 \r
     if(gameInfo.variant == VariantFischeRandom) {\r
@@ -4283,6 +4336,21 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar)
         return ImpossibleMove;\r
     }\r
 \r
+    /* [HGM] suppress all moves into holdings area and guard band */\r
+    if( toX < BOARD_LEFT || toX >= BOARD_RGHT || toY < 0 )\r
+            return ImpossibleMove;\r
+\r
+    /* [HGM] <sameColor> moved to here from winboard.c */\r
+    /* note: this code seems to exist for filtering out some obviously illegal premoves */\r
+    pdown = boards[currentMove][fromY][fromX];\r
+    pup = boards[currentMove][toY][toX];\r
+    if (    gameMode != EditPosition &&\r
+            (WhitePawn <= pdown && pdown < BlackPawn &&\r
+             WhitePawn <= pup && pup < BlackPawn  ||\r
+             BlackPawn <= pdown && pdown < EmptySquare &&\r
+             BlackPawn <= pup && pup < EmptySquare)      )\r
+         return ImpossibleMove;\r
+\r
     /* Check if the user is playing in turn.  This is complicated because we\r
        let the user "pick up" a piece before it is his turn.  So the piece he\r
        tried to pick up may have been captured by the time he puts it down!\r
@@ -4401,21 +4469,6 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar)
         return ImpossibleMove;\r
     }\r
 \r
-    /* [HGM] suppress all moves into holdings area and guard band */\r
-    if( toX < BOARD_LEFT || toX >= BOARD_RGHT || toY < 0 )\r
-            return ImpossibleMove;\r
-\r
-    /* [HGM] <sameColor> moved to here from winboard.c */\r
-    /* note: EditPosition already filtered out and performed! */\r
-    pdown = boards[currentMove][fromY][fromX];\r
-    pup = boards[currentMove][toY][toX];\r
-    if ( \r
-            (WhitePawn <= pdown && pdown < BlackPawn &&\r
-             WhitePawn <= pup && pup < BlackPawn) ||\r
-            (BlackPawn <= pdown && pdown < EmptySquare &&\r
-             BlackPawn <= pup && pup < EmptySquare)      )\r
-         return ImpossibleMove;\r
-\r
     /* [HGM] If move started in holdings, it means a drop */\r
     if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) { \r
          if( pup != EmptySquare ) return ImpossibleMove;\r
@@ -4758,6 +4811,7 @@ HandleMachineMove(message, cps)
            return;\r
        }\r
 \r
+        AlphaRank(machineMove, 4);\r
         if (!ParseOneMove(machineMove, forwardMostMove, &moveType,\r
                               &fromX, &fromY, &toX, &toY, &promoChar)) {\r
            /* Machine move could not be parsed; ignore it. */\r
@@ -4979,7 +5033,8 @@ HandleMachineMove(message, cps)
                 count = 0;\r
                 for(k = forwardMostMove-2;\r
                     k>=backwardMostMove && k>=forwardMostMove-100 &&\r
-                        epStatus[k] <= EP_NONE && epStatus[k+1] <= EP_NONE;\r
+                        epStatus[k] < EP_UNKNOWN &&\r
+                        epStatus[k+2] <= EP_NONE && epStatus[k+1] <= EP_NONE;\r
                     k-=2)\r
                 {   int rights=0;\r
     if (appData.debugMode) {\r
@@ -5418,6 +5473,10 @@ HandleMachineMove(message, cps)
     } else if (strncmp(message, "Black resign", 12) == 0) {\r
         GameEnds(WhiteWins, "Black resigns", GE_ENGINE1 + (cps != &first));\r
        return;\r
+    } else if (strncmp(message, "White matches", 13) == 0 ||\r
+               strncmp(message, "Black matches", 13) == 0   ) {\r
+        /* [HGM] ignore GNUShogi noises */\r
+        return;\r
     } else if (strncmp(message, "White", 5) == 0 &&\r
               message[5] != '(' &&\r
               StrStr(message, "Black") == NULL) {\r
@@ -5818,12 +5877,16 @@ ParseGameHistory(game)
        yyboardindex = boardIndex;\r
        moveType = (ChessMove) yylex();\r
        switch (moveType) {\r
-#ifdef FAIRY\r
+         case IllegalMove:             /* maybe suicide chess, etc. */\r
+  if (appData.debugMode) {\r
+    fprintf(debugFP, "Illegal move from ICS: '%s'\n", yy_text);\r
+    fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+    setbuf(debugFP, NULL);\r
+  }\r
           case WhitePromotionChancellor:\r
           case BlackPromotionChancellor:\r
           case WhitePromotionArchbishop:\r
           case BlackPromotionArchbishop:\r
-#endif\r
          case WhitePromotionQueen:\r
          case BlackPromotionQueen:\r
          case WhitePromotionRook:\r
@@ -5851,7 +5914,6 @@ ParseGameHistory(game)
           case BlackHSideCastleFR:\r
           case BlackASideCastleFR:\r
           /* POP Fabien */\r
-         case IllegalMove:             /* maybe suicide chess, etc. */\r
             fromX = currentMoveString[0] - AAA;\r
             fromY = currentMoveString[1] - ONE;\r
             toX = currentMoveString[2] - AAA;\r
@@ -5871,11 +5933,21 @@ ParseGameHistory(game)
          case AmbiguousMove:\r
            /* bug? */\r
            sprintf(buf, "Ambiguous move in ICS output: \"%s\"", yy_text);\r
+  if (appData.debugMode) {\r
+    fprintf(debugFP, "Ambiguous move from ICS: '%s'\n", yy_text);\r
+    fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+    setbuf(debugFP, NULL);\r
+  }\r
            DisplayError(buf, 0);\r
            return;\r
          case ImpossibleMove:\r
            /* bug? */\r
            sprintf(buf, "Illegal move in ICS output: \"%s\"", yy_text);\r
+  if (appData.debugMode) {\r
+    fprintf(debugFP, "Impossible move from ICS: '%s'\n", yy_text);\r
+    fprintf(debugFP, "board L=%d, R=%d, H=%d, holdings=%d\n", BOARD_LEFT, BOARD_RGHT, BOARD_HEIGHT, gameInfo.holdingsWidth);\r
+    setbuf(debugFP, NULL);\r
+  }\r
            DisplayError(buf, 0);\r
            return;\r
          case (ChessMove) 0:   /* end of file */\r
@@ -6215,14 +6287,14 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
       if( boards[forwardMostMove][fromY][fromX] == WhitePawn ) {\r
            epStatus[forwardMostMove] = EP_PAWN_MOVE; \r
            if( toY-fromY==2 &&\r
-               (toX>BOARD_LEFT+1 && boards[forwardMostMove][toY][toX-1] == BlackPawn ||\r
+               (toX>BOARD_LEFT   && boards[forwardMostMove][toY][toX-1] == BlackPawn ||\r
                 toX<BOARD_RGHT-1 && boards[forwardMostMove][toY][toX+1] == BlackPawn ) )\r
               epStatus[forwardMostMove] = toX;\r
       } else \r
       if( boards[forwardMostMove][fromY][fromX] == BlackPawn ) {\r
            epStatus[forwardMostMove] = EP_PAWN_MOVE; \r
            if( toY-fromY== -2 &&\r
-               (toX>BOARD_LEFT+1 && boards[forwardMostMove][toY][toX-1] == WhitePawn ||\r
+               (toX>BOARD_LEFT   && boards[forwardMostMove][toY][toX-1] == WhitePawn ||\r
                 toX<BOARD_RGHT-1 && boards[forwardMostMove][toY][toX+1] == WhitePawn ) )\r
               epStatus[forwardMostMove] = toX;\r
        }\r
@@ -6233,6 +6305,8 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
               castlingRights[forwardMostMove][i] == toX   && castlingRank[i] == toY   \r
              ) castlingRights[forwardMostMove][i] = -1; // revoke for moved or captured piece\r
 \r
+\r
+\r
        }\r
 \r
     }\r
@@ -6543,8 +6617,9 @@ GameEnds(result, resultDetails, whosays)
                 claimer = whosays == GE_ENGINE1 ?      /* color of claimer */\r
                                             first.twoMachinesColor[0] :\r
                                             second.twoMachinesColor[0] ;\r
-                if( result == WhiteWins && claimer == 'w' ||\r
-                    result == BlackWins && claimer == 'b' ) {\r
+                if( gameInfo.holdingsWidth == 0 &&\r
+                    (result == WhiteWins && claimer == 'w' ||\r
+                     result == BlackWins && claimer == 'b'   ) ) {\r
                       /* Xboard immediately adjudicates all mates, so win claims must be false */\r
                       sprintf(buf, "False win claim: '%s'", resultDetails);\r
                       result = claimer == 'w' ? BlackWins : WhiteWins;\r
@@ -11703,22 +11778,16 @@ PositionToFEN(move, useFEN960)
                     else { *p++ = '0' + emptycount/10; *p++ = '0' + emptycount%10; }\r
                    emptycount = 0;\r
                }\r
-                if(gameInfo.variant == VariantShogi) {\r
-                    /* [HGM] write Shogi promoted pieces as +<unpromoted> */\r
-                    if( (int)piece > (int) WhiteCannon && (int)piece < (int) WhiteKing ||\r
-                        (int)piece > (int) BlackCannon && (int)piece < (int) BlackKing ) {\r
-                        *p++ = '+';\r
-                        piece = (ChessSquare)(DEMOTED piece);\r
-                    }\r
+                if(PieceToChar(piece) == '+') {\r
+                    /* [HGM] write promoted pieces as '+<unpromoted>' (Shogi) */\r
+                    *p++ = '+';\r
+                    piece = (ChessSquare)(DEMOTED piece);\r
                 } \r
                 *p++ = PieceToChar(piece);\r
-                if(gameInfo.variant == VariantCrazyhouse || gameInfo.variant == VariantBughouse) {\r
-                    /* [HGM] flag Crazyhouse promoted pieces */\r
-                    if( (int)piece > (int) WhiteQueen && (int)piece < (int) WhiteKing ||\r
-                        (int)piece > (int) BlackQueen && (int)piece < (int) BlackKing ) {\r
-                        p[-1] = PieceToChar((ChessSquare)(DEMOTED piece));\r
-                        *p++ = '~';\r
-                    }\r
+                if(p[-1] == '~') {\r
+                    /* [HGM] flag promoted pieces as '<promoted>~' (Crazyhouse) */\r
+                    p[-1] = PieceToChar((ChessSquare)(DEMOTED piece));\r
+                    *p++ = '~';\r
                 }\r
            }\r
        }\r
@@ -11736,6 +11805,7 @@ PositionToFEN(move, useFEN960)
     *p++ = whiteToPlay ? 'w' : 'b';\r
     *p++ = ' ';\r
 \r
+  if(nrCastlingRights) {\r
     /* HACK: we don't keep track of castling availability, so fake it! */\r
     /* Tord! please fix with the aid of castlingRights[move][...] */\r
 \r
@@ -11826,7 +11896,10 @@ PositionToFEN(move, useFEN960)
     }\r
 \r
     /* POP Fabien & Tord */\r
+  }\r
 \r
+  if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&\r
+     gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { \r
     /* En passant target square */\r
     if (move > backwardMostMove) {\r
         fromX = moveList[move - 1][0] - AAA;\r
@@ -11846,10 +11919,12 @@ PositionToFEN(move, useFEN960)
     } else {\r
        *p++ = '-';\r
     }\r
+    *p++ = ' ';\r
+  }\r
 \r
     /* [HGM] print Crazyhouse or Shogi holdings */\r
     if( gameInfo.holdingsWidth ) {\r
-        *p++ = ' '; q = p;\r
+        q = p;\r
         for(i=0; i<gameInfo.holdingsSize; i++) { /* white holdings */\r
             piece = boards[move][i][BOARD_WIDTH-1];\r
             if( piece != EmptySquare )\r
@@ -11870,20 +11945,20 @@ PositionToFEN(move, useFEN960)
     /* [HGM] find reversible plies */\r
     {   int i = 0, j=move;\r
 \r
-    if (appData.debugMode) { int k;\r
-        fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);\r
-        for(k=backwardMostMove; k<=forwardMostMove; k++)\r
-            fprintf(debugFP, "e%d. p=%d\n", k, epStatus[k]);\r
+        if (appData.debugMode) { int k;\r
+            fprintf(debugFP, "write FEN 50-move: %d %d %d\n", initialRulePlies, forwardMostMove, backwardMostMove);\r
+            for(k=backwardMostMove; k<=forwardMostMove; k++)\r
+                fprintf(debugFP, "e%d. p=%d\n", k, epStatus[k]);\r
 \r
-    }\r
+        }\r
 \r
         while(j > backwardMostMove && epStatus[j] <= EP_NONE) j--,i++;\r
         if( j == backwardMostMove ) i += initialRulePlies;\r
-        sprintf(p, " %d", i);\r
-      p += i>=100 ? 4 : i >= 10 ? 3 : 2;\r
+        sprintf(p, "%d ", i);\r
+        p += i>=100 ? 4 : i >= 10 ? 3 : 2;\r
     }\r
     /* Fullmove number */\r
-    sprintf(p, " %d", (move / 2) + 1);\r
+    sprintf(p, "%d", (move / 2) + 1);\r
     \r
     return StrSave(buf);\r
 }\r
@@ -11902,14 +11977,14 @@ ParseFEN(board, blackPlaysFirst, fen)
     p = fen;\r
 \r
     /* [HGM] by default clear Crazyhouse holdings, if present */\r
-   if(gameInfo.holdingsWidth) {\r
+    if(gameInfo.holdingsWidth) {\r
        for(i=0; i<BOARD_HEIGHT; i++) {\r
            board[i][0]             = EmptySquare; /* black holdings */\r
            board[i][BOARD_WIDTH-1] = EmptySquare; /* white holdings */\r
            board[i][1]             = (ChessSquare) 0; /* black counts */\r
            board[i][BOARD_WIDTH-2] = (ChessSquare) 0; /* white counts */\r
        }\r
-   }\r
+    }\r
 \r
     /* Piece placement data */\r
     for (i = BOARD_HEIGHT - 1; i >= 0; i--) {\r
@@ -11936,10 +12011,17 @@ ParseFEN(board, blackPlaysFirst, fen)
                         board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;\r
             } else if (*p == '+' || isalpha(*p)) {\r
                 if (j >= gameInfo.boardWidth) return FALSE;\r
-                if(*p=='+') { piece = (ChessSquare) (PROMOTED CharToPiece(*++p) ); p++; }\r
-                else piece = CharToPiece(*p++);\r
+                if(*p=='+') {\r
+                    piece = CharToPiece(*++p);\r
+                    if(piece == EmptySquare) return FALSE; /* unknown piece */\r
+                    piece = (ChessSquare) (PROMOTED piece ); p++;\r
+                    if(PieceToChar(piece) != '+') return FALSE; /* unpromotable piece */\r
+                } else piece = CharToPiece(*p++);\r
+\r
+                if(piece==EmptySquare) return FALSE; /* unknown piece */\r
                 if(*p == '~') { /* [HGM] make it a promoted piece for Crazyhouse */\r
                     piece = (ChessSquare) (PROMOTED piece);\r
+                    if(PieceToChar(piece) != '~') return FALSE; /* cannot be a promoted piece */\r
                     p++;\r
                 }\r
                 board[i][(j++)+gameInfo.holdingsWidth] = piece;\r
@@ -11964,7 +12046,7 @@ ParseFEN(board, blackPlaysFirst, fen)
 \r
     /* [HGM] We NO LONGER ignore the rest of the FEN notation */\r
     /* return the extra info in global variiables             */\r
-  {\r
+\r
     /* set defaults in case FEN is incomplete */\r
     FENepStatus = EP_UNKNOWN;\r
     for(i=0; i<nrCastlingRights; i++ ) {\r
@@ -11979,14 +12061,14 @@ ParseFEN(board, blackPlaysFirst, fen)
     FENrulePlies = 0;\r
 \r
     while(*p==' ') p++;\r
-\r
-    if(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
-              /* castling indicator present, so default is no castlings */\r
-              for(i=0; i<nrCastlingRights; i++ ) {\r
-                     FENcastlingRights[i] = -1;\r
-              }\r
-    }\r
-    while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
+    if(nrCastlingRights) {\r
+      if(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
+          /* castling indicator present, so default becomes no castlings */\r
+          for(i=0; i<nrCastlingRights; i++ ) {\r
+                 FENcastlingRights[i] = -1;\r
+          }\r
+      }\r
+      while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-') {\r
         switch(*p++) {\r
           case'K':\r
               FENcastlingRights[0] = BOARD_RGHT-1;\r
@@ -12006,24 +12088,28 @@ ParseFEN(board, blackPlaysFirst, fen)
               break;\r
           /* Tord! FRC! */\r
         }\r
-    }\r
-\r
-    while(*p==' ') p++;\r
+      }\r
 \r
+      while(*p==' ') p++;\r
+    }\r
 \r
-    if(*p=='-') {\r
+    /* read e.p. field in games that know e.p. capture */\r
+    if(gameInfo.variant != VariantShogi    && gameInfo.variant != VariantXiangqi &&\r
+       gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier ) { \r
+      if(*p=='-') {\r
         p++; FENepStatus = EP_NONE;\r
-    } else {\r
-       char c = *p++ - AAA;\r
+      } else {\r
+         char c = *p++ - AAA;\r
 \r
-       if(c < BOARD_LEFT || c >= BOARD_RGHT) return TRUE;\r
-       if(*p >= '0' && *p <='9') *p++;\r
-       FENepStatus = c;\r
+         if(c < BOARD_LEFT || c >= BOARD_RGHT) return TRUE;\r
+         if(*p >= '0' && *p <='9') *p++;\r
+         FENepStatus = c;\r
+      }\r
     }\r
 \r
     /* [HGM] look for Crazyhouse holdings here */\r
     while(*p==' ') p++;\r
-    if( !isdigit(*p) ) {\r
+    if( gameInfo.holdingsWidth ) {\r
         if(*p == '-' ) *p++; /* empty holdings */ else {\r
             if( !gameInfo.holdingsWidth ) return FALSE; /* no room to put holdings! */\r
             /* if we would allow FEN reading to set board size, we would   */\r
@@ -12046,12 +12132,11 @@ ParseFEN(board, blackPlaysFirst, fen)
     }\r
 \r
 \r
-\r
     if(sscanf(p, "%d", &i) == 1) {\r
         FENrulePlies = i; /* 50-move ply counter */\r
         /* (The move number is still ignored)    */\r
     }\r
- }\r
+\r
     return TRUE;\r
 }\r
       \r