fix joining of lines split by ICS
[xboard.git] / backend.c
index 6cba815..a612db1 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -2124,7 +2124,8 @@ read_from_ics(isr, closure, data, count, error)
            if(buf_len >= 5 && buf[buf_len-5]=='\n' && buf[buf_len-4]=='\\' && 
                                buf[buf_len-3]==' '  && buf[buf_len-2]==' '  && buf[buf_len-1]==' ') {
                buf_len -= 5; // [HGM] ICS: join continuation line of Lasker 2.2.3 server with previous
-               buf[buf_len++] = ' '; // replace by space (assumes ICS does not break lines within word)
+               if(buf_len == 0 || buf[buf_len-1] != ' ')
+                  buf[buf_len++] = ' '; // add space (assumes ICS does not break lines within word)
            }
        }
 
@@ -5050,38 +5051,37 @@ int lastLoadGameUseList = FALSE;
 char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ];
 ChessMove lastLoadGameStart = (ChessMove) 0;
 
-
 ChessMove
-UserMoveTest(fromX, fromY, toX, toY, promoChar)
+UserMoveTest(fromX, fromY, toX, toY, promoChar, captureOwn)
      int fromX, fromY, toX, toY;
      int promoChar;
+     Boolean captureOwn;
 {
     ChessMove moveType;
     ChessSquare pdown, pup;
 
     if (fromX < 0 || fromY < 0) return ImpossibleMove;
-    if ((fromX == toX) && (fromY == toY)) {
-        return ImpossibleMove;
-    }
 
     /* [HGM] suppress all moves into holdings area and guard band */
     if( toX < BOARD_LEFT || toX >= BOARD_RGHT || toY < 0 )
             return ImpossibleMove;
 
     /* [HGM] <sameColor> moved to here from winboard.c */
-    /* note: this code seems to exist for filtering out some obviously illegal premoves */
+    /* note: capture of own piece can be legal as drag-drop premove. For click-click it is selection of new piece. */
     pdown = boards[currentMove][fromY][fromX];
     pup = boards[currentMove][toY][toX];
-    if (    gameMode != EditPosition &&
+    if (    gameMode != EditPosition && !captureOwn &&
             (WhitePawn <= pdown && pdown < BlackPawn &&
              WhitePawn <= pup && pup < BlackPawn  ||
              BlackPawn <= pdown && pdown < EmptySquare &&
              BlackPawn <= pup && pup < EmptySquare 
             ) && !((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) &&
                     (pup == WhiteRook && pdown == WhiteKing && fromY == 0 && toY == 0||
-                     pup == BlackRook && pdown == BlackKing && fromY == BOARD_HEIGHT-1 && toY == BOARD_HEIGHT-1  ) 
+                     pup == BlackRook && pdown == BlackKing && fromY == BOARD_HEIGHT-1 && toY == BOARD_HEIGHT-1 ||
+                     pup == WhiteKing && pdown == WhiteRook && fromY == 0 && toY == 0|| // also allow RxK
+                     pup == BlackKing && pdown == BlackRook && fromY == BOARD_HEIGHT-1 && toY == BOARD_HEIGHT-1  ) 
         )           )
-         return ImpossibleMove;
+         return Comment;
 
     /* Check if the user is playing in turn.  This is complicated because we
        let the user "pick up" a piece before it is his turn.  So the piece he
@@ -5222,7 +5222,6 @@ UserMoveTest(fromX, fromY, toX, toY, promoChar)
     moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
                           epStatus[currentMove], castlingRights[currentMove],
                                          fromY, fromX, toY, toX, promoChar);
-
     /* [HGM] but possibly ignore an IllegalMove result */
     if (appData.testLegality) {
        if (moveType == IllegalMove || moveType == ImpossibleMove) {
@@ -5438,11 +5437,11 @@ UserMoveEvent(fromX, fromY, toX, toY, promoChar)
        FinishMove if the first part succeeded. Calls that do not need
        to do anything in between, can call this routine the old way. 
     */
-    ChessMove moveType = UserMoveTest(fromX, fromY, toX, toY, promoChar);
+    ChessMove moveType = UserMoveTest(fromX, fromY, toX, toY, promoChar, FALSE);
 if(appData.debugMode) fprintf(debugFP, "moveType 4 = %d, promochar = %x\n", moveType, promoChar);
     if(moveType == AmbiguousMove)
        DrawPosition(FALSE, boards[currentMove]);
-    else if(moveType != ImpossibleMove)
+    else if(moveType != ImpossibleMove && moveType != Comment)
         FinishMove(moveType, fromX, fromY, toX, toY, promoChar);
 }
 
@@ -6378,6 +6377,29 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.
        }
 #endif
        if (pausing) PauseEvent();
+      if(appData.forceIllegal) {
+           // [HGM] illegal: machine refused move; force position after move into it
+          SendToProgram("force\n", cps);
+          if(!cps->useSetboard) { // hideous kludge on kludge, because SendBoard sucks.
+               // we have a real problem now, as SendBoard will use the a2a3 kludge
+               // when black is to move, while there might be nothing on a2 or black
+               // might already have the move. So send the board as if white has the move.
+               // But first we must change the stm of the engine, as it refused the last move
+               SendBoard(cps, 0); // always kludgeless, as white is to move on boards[0]
+               if(WhiteOnMove(forwardMostMove)) {
+                   SendToProgram("a7a6\n", cps); // for the engine black still had the move
+                   SendBoard(cps, forwardMostMove); // kludgeless board
+               } else {
+                   SendToProgram("a2a3\n", cps); // for the engine white still had the move
+                   CopyBoard(boards[forwardMostMove+1], boards[forwardMostMove]);
+                   SendBoard(cps, forwardMostMove+1); // kludgeless board
+               }
+          } else SendBoard(cps, forwardMostMove); // FEN case, also sets stm properly
+           if(gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
+                gameMode == TwoMachinesPlay)
+              SendToProgram("go\n", cps);
+           return;
+      } else
        if (gameMode == PlayFromGameFile) {
            /* Stop reading this game file */
            gameMode = EditGame;
@@ -7453,9 +7475,6 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
                        0, 1);
       return;
     }
-    SwitchClocks();
-    timeRemaining[0][forwardMostMove+1] = whiteTimeRemaining;
-    timeRemaining[1][forwardMostMove+1] = blackTimeRemaining;
     if (commentList[forwardMostMove+1] != NULL) {
        free(commentList[forwardMostMove+1]);
        commentList[forwardMostMove+1] = NULL;
@@ -7465,6 +7484,9 @@ MakeMove(fromX, fromY, toX, toY, promoChar)
     ApplyMove(fromX, fromY, toX, toY, promoChar, boards[forwardMostMove+1], 
                                castlingRights[forwardMostMove+1], &epStatus[forwardMostMove+1]);
     forwardMostMove++; // [HGM] bare: moved to after ApplyMove, to make sure clock interrupt finds complete board
+    SwitchClocks(); // uses forwardMostMove, so must be done after incrementing it !
+    timeRemaining[0][forwardMostMove] = whiteTimeRemaining;
+    timeRemaining[1][forwardMostMove] = blackTimeRemaining;
     gameInfo.result = GameUnfinished;
     if (gameInfo.resultDetails != NULL) {
        free(gameInfo.resultDetails);