Implement non-royal castling
[xboard.git] / backend.c
index cb564b4..dd8bbb1 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -7501,6 +7501,7 @@ LeftClick (ClickType clickType, int xPix, int yPix)
        toP = boards[currentMove][y][x];
        frc = appData.fischerCastling || gameInfo.variant == VariantSChess;
        if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect!
+           legal[y][x] == 0 && // if engine told we can move to here, do it even if own piece
           ((WhitePawn <= fromP && fromP <= WhiteKing &&
             WhitePawn <= toP && toP <= WhiteKing &&
             !(fromP == WhiteKing && toP == WhiteRook && frc) &&
@@ -9889,7 +9890,7 @@ ParseGameHistory (char *game)
 void
 ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
 {
-  ChessSquare captured = board[toY][toX], piece, king; int p, rookX, oldEP = EP_NONE, berolina = 0;
+  ChessSquare captured = board[toY][toX], piece, king, killed; int p, rookX, oldEP = EP_NONE, berolina = 0;
   int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1;
 
     /* [HGM] compute & store e.p. status and castling rights for new position */
@@ -9913,6 +9914,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
 
       if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something
 //           victim = board[killY][killX],
+           killed = board[killY][killX],
            board[killY][killX] = EmptySquare,
            board[EP_STATUS] = EP_CAPTURE;
 
@@ -9925,15 +9927,18 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
            }
       }
 
-      if( board[fromY][fromX] == WhiteLance || board[fromY][fromX] == BlackLance ) {
-           if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi )
-               board[EP_STATUS] = EP_PAWN_MOVE; // Lance is Pawn-like in most variants
-      } else
-      if( board[fromY][fromX] == WhitePawn ) {
+      piece = board[fromY][fromX];
+      if( piece == WhiteLance || piece == BlackLance ) {
+           if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu ) {
+               if(gameInfo.variant == VariantSpartan) board[EP_STATUS] = EP_PAWN_MOVE; // in Spartan no e.p. rights must be set
+               else piece += WhiteLance - WhitePawn; // Lance is Pawn-like in most variants, so let Pawn code treat it by this kludge
+           }
+      }
+      if( piece == WhitePawn ) {
            if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers
               board[EP_STATUS] = EP_PAWN_MOVE;
-           if( toY-fromY==2) {
-               board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = (fromY + toY)/2;
+           if( toY-fromY>=2) {
+               board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = toY - 1 | 128*(toY - fromY > 2);
                if(toX>BOARD_LEFT   && board[toY][toX-1] == BlackPawn &&
                        gameInfo.variant != VariantBerolina || toX < fromX)
                      board[EP_STATUS] = toX | berolina;
@@ -9942,11 +9947,11 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
                      board[EP_STATUS] = toX;
           }
       } else
-      if( board[fromY][fromX] == BlackPawn ) {
+      if( piece == BlackPawn ) {
            if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers
               board[EP_STATUS] = EP_PAWN_MOVE;
-           if( toY-fromY== -2) {
-               board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = (fromY + toY)/2;
+           if( toY-fromY<= -2) {
+               board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = toY + 1 | 128*(fromY - toY > 2);
                if(toX>BOARD_LEFT   && board[toY][toX-1] == WhitePawn &&
                        gameInfo.variant != VariantBerolina || toX < fromX)
                      board[EP_STATUS] = toX | berolina;
@@ -9981,6 +9986,12 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
      if(gameInfo.variant == VariantKnightmate)
          king += (int) WhiteUnicorn - (int) WhiteKing;
 
+    if(piece != WhiteKing && piece != BlackKing && pieceDesc[piece] && killX >= 0 && strchr(pieceDesc[piece], 'O') // Betza castling-enabled
+       && (piece < BlackPawn ? killed < BlackPawn : killed >= BlackPawn)) {    // and captures own
+       board[toY][toX] = piece; board[fromY][fromX] = EmptySquare;
+       board[toY][toX + (killX < fromX ? 1 : -1)] = killed;
+        board[EP_STATUS] = EP_NONE; // capture was fake!
+    } else
     /* Code added by Tord: */
     /* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */
     if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook ||
@@ -10039,8 +10050,10 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
               && (board[toY][toX] == EmptySquare)) {
        board[fromY][fromX] = EmptySquare;
        board[toY][toX] = WhitePawn;
-       captured = board[toY - 1][toX];
-       board[toY - 1][toX] = EmptySquare;
+       if(toY == board[EP_RANK] - 128 + 1)
+           captured = board[toY - 2][toX], board[toY - 2][toX] = EmptySquare;
+       else
+           captured = board[toY - 1][toX], board[toY - 1][toX] = EmptySquare;
     } else if ((fromY == BOARD_HEIGHT-4)
               && (toX == fromX)
                && gameInfo.variant == VariantBerolina
@@ -10102,8 +10115,10 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board)
               && (board[toY][toX] == EmptySquare)) {
        board[fromY][fromX] = EmptySquare;
        board[toY][toX] = BlackPawn;
-       captured = board[toY + 1][toX];
-       board[toY + 1][toX] = EmptySquare;
+       if(toY == board[EP_RANK] - 128 - 1)
+           captured = board[toY + 2][toX], board[toY + 2][toX] = EmptySquare;
+       else
+           captured = board[toY + 1][toX], board[toY + 1][toX] = EmptySquare;
     } else if ((fromY == 3)
               && (toX == fromX)
                && gameInfo.variant == VariantBerolina