Implement check-count field in FENs
[xboard.git] / backend.c
index 12aadc1..9973c37 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -6451,6 +6451,7 @@ InitPosition (int redraw)
       initialPosition[1][1] = initialPosition[2][1] =
       initialPosition[6][BOARD_WIDTH-2] = initialPosition[5][BOARD_WIDTH-2] = 1;
      }
+     initialPosition[CHECK_COUNT] = (gameInfo.variant == Variant3Check ? 0x303 : 0);
   if (appData.debugMode) {
     fprintf(debugFP, "shuffleOpenings = %d\n", shuffleOpenings);
   }
@@ -7462,7 +7463,7 @@ MarkTargetSquares (int clear)
     if(PosFlags(0) & F_MANDATORY_CAPTURE) {
       for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x]>1) capt++;
       if(capt)
-      for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x] == 1) marker[y][x] = 0;
+      for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) if(marker[y][x] == 1) marker[y][x] = legal[y][x] = 0;
     }
   }
   DrawPosition(FALSE, NULL);
@@ -10030,7 +10031,7 @@ void
 ParseGameHistory (char *game)
 {
     ChessMove moveType;
-    int fromX, fromY, toX, toY, boardIndex;
+    int fromX, fromY, toX, toY, boardIndex, mask;
     char promoChar;
     char *p, *q;
     char buf[MSG_SIZ];
@@ -10191,15 +10192,18 @@ ParseGameHistory (char *game)
        strcat(moveList[boardIndex], "\n");
        boardIndex++;
        ApplyMove(fromX, fromY, toX, toY, promoChar, boards[boardIndex]);
+       mask = (WhiteOnMove(boardIndex) ? 0xFF : 0xFF00);
         switch (MateTest(boards[boardIndex], PosFlags(boardIndex)) ) {
          case MT_NONE:
          case MT_STALEMATE:
          default:
            break;
          case MT_CHECK:
-            if(!IS_SHOGI(gameInfo.variant))
-                strcat(parseList[boardIndex - 1], "+");
-           break;
+            if(boards[boardIndex][CHECK_COUNT]) boards[boardIndex][CHECK_COUNT] -= mask & 0x101;
+            if(!boards[boardIndex][CHECK_COUNT] || boards[boardIndex][CHECK_COUNT] & mask) {
+                if(!IS_SHOGI(gameInfo.variant)) strcat(parseList[boardIndex - 1], "+");
+                break;
+           }
          case MT_CHECKMATE:
          case MT_STAINMATE:
            strcat(parseList[boardIndex - 1], "#");
@@ -10220,9 +10224,9 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
     /* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */
 
       if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A;
-      oldEP = (signed char)board[EP_STATUS]; epRank = board[EP_RANK]; epFile = board[EP_FILE]; lastFile = board[LAST_FILE],lastRank = board[LAST_RANK];
+      oldEP = (signed char)board[EP_STATUS]; epRank = board[EP_RANK]; epFile = board[EP_FILE]; lastFile = board[LAST_TO] & 255,lastRank = board[LAST_TO] >> 8;
       board[EP_STATUS] = EP_NONE;
-      board[EP_FILE] = board[EP_RANK] = board[LAST_FILE] = board[LAST_RANK] = 100;
+      board[EP_FILE] = board[EP_RANK] = 100, board[LAST_TO] = 0x4040;
 
   if (fromY == DROP_RANK) {
        /* must be first */
@@ -10278,7 +10282,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
                if(toX<BOARD_RGHT-1 && board[toY][toX+1] == BlackPawn &&
                        gameInfo.variant != VariantBerolina || toX > fromX)
                      board[EP_STATUS] = toX;
-              board[LAST_FILE] = toX; board[LAST_RANK] = toY;
+              board[LAST_TO] = toX + 256*toY;
           }
       } else
       if( pawn == BlackPawn ) {
@@ -10292,7 +10296,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
                if(toX<BOARD_RGHT-1 && board[toY][toX+1] == WhitePawn &&
                        gameInfo.variant != VariantBerolina || toX > fromX)
                      board[EP_STATUS] = toX;
-              board[LAST_FILE] = toX; board[LAST_RANK] = toY;
+              board[LAST_TO] = toX + 256*toY;
           }
        }
 
@@ -10589,7 +10593,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
 void
 MakeMove (int fromX, int fromY, int toX, int toY, int promoChar)
 {
-    int x = toX, y = toY;
+    int x = toX, y = toY, mask;
     char *s = parseList[forwardMostMove];
     ChessSquare p = boards[forwardMostMove][toY][toX];
 //    forwardMostMove++; // [HGM] bare: moved downstream
@@ -10685,15 +10689,18 @@ MakeMove (int fromX, int fromY, int toX, int toY, int promoChar)
     }
     CoordsToComputerAlgebraic(fromY, fromX, toY, toX, promoChar,
                              moveList[forwardMostMove - 1]);
+    mask = (WhiteOnMove(forwardMostMove) ? 0xFF : 0xFF00);
     switch (MateTest(boards[forwardMostMove], PosFlags(forwardMostMove)) ) {
       case MT_NONE:
       case MT_STALEMATE:
       default:
        break;
       case MT_CHECK:
-        if(!IS_SHOGI(gameInfo.variant))
-            strcat(parseList[forwardMostMove - 1], "+");
-       break;
+        if(boards[forwardMostMove][CHECK_COUNT]) boards[forwardMostMove][CHECK_COUNT] -= mask & 0x101;
+       if(!boards[forwardMostMove][CHECK_COUNT] || boards[forwardMostMove][CHECK_COUNT] & mask) {
+            if(!IS_SHOGI(gameInfo.variant)) strcat(parseList[forwardMostMove - 1], "+");
+            break;
+        }
       case MT_CHECKMATE:
       case MT_STAINMATE:
        strcat(parseList[forwardMostMove - 1], "#");
@@ -11274,9 +11281,9 @@ void
 SaveEngineSettings (int n)
 {
     int len; char *p, *q, *s, buf[MSG_SIZ], *optionSettings;
-    if(!currentEngine[n] || !currentEngine[n][0]) return; // no engine from list is loaded
+    if(!currentEngine[n] || !currentEngine[n][0]) { DisplayMessage("saving failed: engine not from list", ""); return; } // no engine from list is loaded
     p = strstr(firstChessProgramNames, currentEngine[n]);
-    if(!p) return; // sanity check; engine could be deleted from list after loading
+    if(!p) { DisplayMessage("saving failed: engine not found in list", ""); return; } // sanity check; engine could be deleted from list after loading
     optionSettings = ResendOptions(n ? &second : &first, FALSE);
     len = strlen(currentEngine[n]);
     q = p + len; *p = 0; // cut list into head and tail piece
@@ -11343,6 +11350,7 @@ GetEngineLine (char *s, int n)
     if(n == 1) SwapEngines(n);
     ParseArgsFromString(buf);
     if(n == 1) SwapEngines(n);
+    if(n < 2) { ASSIGN(currentEngine[n], command[i]); }
     if(n == 0 && *appData.secondChessProgram == NULLCHAR) {
        SwapEngines(1); // set second same as first if not yet set (to suppress WB startup dialog)
        ParseArgsFromString(buf);
@@ -18459,6 +18467,12 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts)
   }
   }
 
+    i = boards[move][CHECK_COUNT];
+    if(i) {
+       sprintf(p, "%d+%d ", i&255, i>>8);
+       while(*p) p++;
+    }
+
     if(moveCounts)
     {   int i = 0, j=move;
 
@@ -18819,10 +18833,19 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
       }
     }
 
+    while(*p == ' ') p++;
+
+    board[CHECK_COUNT] = 0; // [HGM] 3check: check-count field
+    if(sscanf(p, "%d+%d", &i, &j) == 2) {
+       board[CHECK_COUNT] = i + 256*j;
+       while(*p && *p != ' ') p++;
+    }
 
-    if(sscanf(p, "%d", &i) == 1) {
+    c = sscanf(p, "%d%*d +%d+%d", &i, &j, &k);
+    if(c > 0) {
         FENrulePlies = i; /* 50-move ply counter */
         /* (The move number is still ignored)    */
+       if(c == 3 && !board[CHECK_COUNT]) board[CHECK_COUNT] = (3 - j) + 256*(3 - k); // SCIDB-style check count
     }
 
     return TRUE;