Fix u64 format for cygwin
[xboard.git] / backend.c
old mode 100755 (executable)
new mode 100644 (file)
index 4208beb..1e0bf93
--- a/backend.c
+++ b/backend.c
@@ -187,6 +187,7 @@ void DisplayMove P((int moveNumber));
 
 void ParseGameHistory P((char *game));
 void ParseBoard12 P((char *string));
+void KeepAlive P((void));
 void StartClocks P((void));
 void SwitchClocks P((void));
 void StopClocks P((void));
@@ -242,6 +243,7 @@ char endingGame = 0;    /* [HGM] crash: flag to prevent recursion of GameEnds()
 int whiteNPS, blackNPS; /* [HGM] nps: for easily making clocks aware of NPS     */
 VariantClass currentlyInitializedVariant; /* [HGM] variantswitch */
 int lastIndex = 0;      /* [HGM] autoinc: last game/position used in match mode */
+Boolean connectionAlive;/* [HGM] alive: ICS connection status from probing      */
 int opponentKibitzes;
 int lastSavedGame; /* [HGM] save: ID of game */
 char chatPartner[MAX_CHAT][MSG_SIZ]; /* [HGM] chat: list of chatting partners */
@@ -743,7 +745,7 @@ InitBackEnd1()
     /* [HGM] time odds: set factor for each machine */
     first.timeOdds  = appData.firstTimeOdds;
     second.timeOdds = appData.secondTimeOdds;
-    { int norm = 1;
+    { float norm = 1;
         if(appData.timeOddsMode) {
             norm = first.timeOdds;
             if(norm > second.timeOdds) norm = second.timeOdds;
@@ -1097,6 +1099,8 @@ InitBackEnd3 P((void))
          AddInputSource(icsPR, FALSE, read_from_ics, &telnetISR);
        fromUserISR =
          AddInputSource(NoProc, FALSE, read_from_player, &fromUserISR);
+       if(appData.keepAlive) // [HGM] alive: schedule sending of dummy 'date' command
+           ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000);
     } else if (appData.noChessProgram) {
        SetNCPMode();
     } else {
@@ -1417,6 +1421,8 @@ read_from_player(isr, closure, message, count, error)
 void
 KeepAlive()
 {   // [HGM] alive: periodically send dummy (date) command to ICS to prevent time-out
+    if(!connectionAlive) DisplayFatalError("No response from ICS", 0, 1);
+    connectionAlive = FALSE; // only sticks if no response to 'date' command.
     SendToICS("date\n");
     if(appData.keepAlive) ScheduleDelayedEvent(KeepAlive, appData.keepAlive*60*1000);
 }
@@ -2042,7 +2048,7 @@ read_from_ics(isr, closure, data, count, error)
      int count;
      int error;
 {
-#define BUF_SIZE 8192
+#define BUF_SIZE (16*1024) /* overflowed at 8K with "inchannel 1" on FICS? */
 #define STARTED_NONE 0
 #define STARTED_MOVES 1
 #define STARTED_BOARD 2
@@ -2071,6 +2077,8 @@ read_from_ics(isr, closure, data, count, error)
     char talker[MSG_SIZ]; // [HGM] chat
     int channel;
 
+    connectionAlive = TRUE; // [HGM] alive: I think, therefore I am...
+
     if (appData.debugMode) {
       if (!error) {
        fprintf(debugFP, "<ICS: ");
@@ -3700,6 +3708,11 @@ ParseBoard12(string)
         for(k=BOARD_LEFT; k<BOARD_RGHT; k++)
             if(board[BOARD_HEIGHT-1][k] == bKing)
                 initialRights[5] = castlingRights[moveNum][5] = k;
+        if(gameInfo.variant == VariantTwoKings) {
+            // In TwoKings looking for a King does not work, so always give castling rights to a King on e1/e8
+            if(board[0][4] == wKing) initialRights[2] = castlingRights[moveNum][2] = 4;
+            if(board[BOARD_HEIGHT-1][4] == bKing) initialRights[5] = castlingRights[moveNum][5] = 4;
+        }
     } else { int r;
         r = castlingRights[moveNum][0] = initialRights[0];
         if(board[0][r] != WhiteRook) castlingRights[moveNum][0] = -1;
@@ -4349,7 +4362,7 @@ ParseOneMove(move, moveNum, moveType, fromX, fromY, toX, toY, promoChar)
        if (appData.testLegality) {
          return (*moveType != IllegalMove);
        } else {
-         return !(fromX == fromY && toX == toY);
+         return !(*fromX == *toX && *fromY == *toY);
        }
 
       case WhiteDrop:
@@ -4713,7 +4726,7 @@ InitPosition(redraw)
       break;
     case VariantFairy:
       pieces = fairyArray;
-      SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk"); 
+      SetCharTable(pieceToChar, "PNBRQFEACWMOHIJGDVLSUKpnbrqfeacwmohijgdvlsuk"); 
       break;
     case VariantGreat:
       pieces = GreatArray;
@@ -5346,7 +5359,7 @@ FinishMove(moveType, fromX, fromY, toX, toY, promoChar)
         moveType = PromoCharToMoveType(WhiteOnMove(currentMove), promoChar);
 
     /* [HGM] convert drag-and-drop piece drops to standard form */
-    if( fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) {
+    if( (fromX == BOARD_LEFT-2 || fromX == BOARD_RGHT+1) && fromY != DROP_RANK ){
          moveType = WhiteOnMove(currentMove) ? WhiteDrop : BlackDrop;
           if(appData.debugMode) fprintf(debugFP, "Drop move %d, curr=%d, x=%d,y=%d, p=%d\n", 
                moveType, currentMove, fromX, fromY, boards[currentMove][fromY][fromX]);
@@ -6924,7 +6937,12 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
 
                 /* [AS] Negate score if machine is playing black and reporting absolute scores */
                 if( cps->scoreIsAbsolute && 
-                    ((gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b')) )
+                    ( gameMode == MachinePlaysBlack ||
+                      gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b' ||
+                      gameMode == IcsPlayingBlack ||     // [HGM] also add other situations where engine should report black POV
+                     (gameMode == AnalyzeMode || gameMode == AnalyzeFile || gameMode == IcsObserving && appData.icsEngineAnalyze) &&
+                     !WhiteOnMove(currentMove)
+                    ) )
                 {
                     curscore = -curscore;
                 }
@@ -12597,7 +12615,7 @@ SendTimeRemaining(cps, machineWhite)
     /* [HGM] translate opponent's time by time-odds factor */
     otime = (otime * cps->other->timeOdds) / cps->timeOdds;
     if (appData.debugMode) {
-        fprintf(debugFP, "time odds: %d %d \n", cps->timeOdds, cps->other->timeOdds);
+        fprintf(debugFP, "time odds: %f %f \n", cps->timeOdds, cps->other->timeOdds);
     }
 
     if (time <= 0) time = 1;
@@ -13678,7 +13696,7 @@ PositionToFEN(move, overrideCastling)
     *p++ = ' ';
 
   if(q = overrideCastling) { // [HGM] FRC: override castling & e.p fields for non-compliant engines
-    while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' ';
+    while(*p++ = *q++); if(q != overrideCastling+1) p[-1] = ' '; else --p;
   } else {
   if(nrCastlingRights) {
      q = p;
@@ -13890,10 +13908,12 @@ ParseFEN(board, blackPlaysFirst, fen)
     }   /* assume possible unless obviously impossible */
     if(initialRights[0]>=0 && board[castlingRank[0]][initialRights[0]] != WhiteRook) FENcastlingRights[0] = -1;
     if(initialRights[1]>=0 && board[castlingRank[1]][initialRights[1]] != WhiteRook) FENcastlingRights[1] = -1;
-    if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1;
+    if(initialRights[2]>=0 && board[castlingRank[2]][initialRights[2]] != WhiteUnicorn
+                          && board[castlingRank[2]][initialRights[2]] != WhiteKing) FENcastlingRights[2] = -1;
     if(initialRights[3]>=0 && board[castlingRank[3]][initialRights[3]] != BlackRook) FENcastlingRights[3] = -1;
     if(initialRights[4]>=0 && board[castlingRank[4]][initialRights[4]] != BlackRook) FENcastlingRights[4] = -1;
-    if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1;
+    if(initialRights[5]>=0 && board[castlingRank[5]][initialRights[5]] != BlackUnicorn
+                          && board[castlingRank[5]][initialRights[5]] != BlackKing) FENcastlingRights[5] = -1;
     FENrulePlies = 0;
 
     while(*p==' ') p++;
@@ -13914,9 +13934,15 @@ ParseFEN(board, blackPlaysFirst, fen)
             if(board[BOARD_HEIGHT-1][i] == BlackKing) blackKingFile = i;
             if(board[0             ][i] == WhiteKing) whiteKingFile = i;
         }
+        if(gameInfo.variant == VariantTwoKings || gameInfo.variant == VariantKnightmate)
+            whiteKingFile = blackKingFile = BOARD_WIDTH >> 1; // scanning fails in these variants
+        if(whiteKingFile<0 || board[0][whiteKingFile]!=WhiteUnicorn
+                           && board[0][whiteKingFile]!=WhiteKing) whiteKingFile = -1;
+        if(blackKingFile<0 || board[BOARD_HEIGHT-1][blackKingFile]!=BlackUnicorn
+                           && board[BOARD_HEIGHT-1][blackKingFile]!=BlackKing) blackKingFile = -1;
         switch(c) {
           case'K':
-              for(i=BOARD_RGHT-1; board[0][i]!=WhiteRook && i>whiteKingFile; i--);
+              for(i=BOARD_RGHT-1; i>whiteKingFile && board[0][i]!=WhiteRook; i--);
               FENcastlingRights[0] = i != whiteKingFile ? i : -1;
               FENcastlingRights[2] = whiteKingFile;
               break;
@@ -13926,7 +13952,7 @@ ParseFEN(board, blackPlaysFirst, fen)
               FENcastlingRights[2] = whiteKingFile;
               break;
           case'k':
-              for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--);
+              for(i=BOARD_RGHT-1; i>blackKingFile && board[BOARD_HEIGHT-1][i]!=BlackRook; i--);
               FENcastlingRights[3] = i != blackKingFile ? i : -1;
               FENcastlingRights[5] = blackKingFile;
               break;
@@ -13963,6 +13989,8 @@ ParseFEN(board, blackPlaysFirst, fen)
               }
         }
       }
+      for(i=0; i<nrCastlingRights; i++)
+        if(FENcastlingRights[i] >= 0) initialRights[i] = FENcastlingRights[i];
     if (appData.debugMode) {
         fprintf(debugFP, "FEN castling rights:");
         for(i=0; i<nrCastlingRights; i++)