Fix Seirawan gating at Rook square in PGN castling moves
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index a53ca59..a6b066b 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -170,7 +170,7 @@ CopyBoard (Board to, Board from)
 {
     int i, j;
 
-    for (i = 0; i < BOARD_HEIGHT; i++)
+    for (i = 0; i < handSize; i++)
       for (j = 0; j < BOARD_WIDTH; j++)
        to[i][j] = from[i][j];
     for (j = 0; j < BOARD_FILES; j++) // [HGM] gamestate: copy castling rights and ep status
@@ -809,9 +809,10 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                               rf, ff, rf + 1, ff + s, closure);
                  }
                  if (rf >= BOARD_HEIGHT+1>>1) {// [HGM] grand: 4th & 5th rank on 10-board
+                     int victimFile = (board[LAST_TO] & 0x40 ? ff + s : board[LAST_TO] & 255);
                       if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
-                         (epfile == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 &&
-                          board[rf][ff + s] == BlackPawn &&
+                         (board[EP_FILE] == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 &&
+                          (board[rf][victimFile] == BlackPawn || board[rf][victimFile] == BlackLance) &&
                           board[rf+1][ff + s] == EmptySquare) {
                          callback(board, flags, WhiteCapturesEnPassant,
                                   rf, ff, rf+1, ff + s, closure);
@@ -859,9 +860,10 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                               rf, ff, rf - 1, ff + s, closure);
                  }
                  if (rf < BOARD_HEIGHT>>1) {
+                     int victimFile = (board[LAST_TO] & 0x40 ? ff + s : board[LAST_TO] & 255);
                       if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
-                         (epfile == ff + s || epfile == EP_UNKNOWN) && rf > 2 &&
-                         board[rf][ff + s] == WhitePawn &&
+                         (board[EP_FILE] == ff + s || epfile == EP_UNKNOWN) && rf > 2 &&
+                         (board[rf][victimFile] == WhitePawn || board[rf][victimFile] == WhiteLance) &&
                          board[rf-1][ff + s] == EmptySquare) {
                          callback(board, flags, BlackCapturesEnPassant,
                                   rf, ff, rf-1, ff + s, closure);
@@ -986,6 +988,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
 
             case WhiteWazir:
             case BlackWazir:
+               if(gameInfo.variant == VariantXiangqi) {
+                   int palace = (piece == WhiteWazir ? 1 : BOARD_HEIGHT-2); // Palace center
+                   if(ff <= BOARD_WIDTH/2 && !SameColor(board[rf][ff+1], piece)) callback(board, flags, NormalMove, rf, ff, rf, ff+1, closure);
+                   if(ff >= BOARD_WIDTH/2 && !SameColor(board[rf][ff-1], piece)) callback(board, flags, NormalMove, rf, ff, rf, ff-1, closure);
+                   if(rf >= palace && !SameColor(board[rf-1][ff], piece)) callback(board, flags, NormalMove, rf, ff, rf-1, ff, closure);
+                   if(rf <= palace && !SameColor(board[rf+1][ff], piece)) callback(board, flags, NormalMove, rf, ff, rf+1, ff, closure);
+                   break;
+               }
                Wazir(board, flags, rf, ff, callback, closure);
                break;
 
@@ -1105,19 +1115,16 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
             /* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */
            case WhiteDragon:
            case BlackDragon:
-              if(gameInfo.variant == VariantChuChess) goto DragonKing;
+              if(gameInfo.variant == VariantChuChess || gameInfo.variant == VariantSpartan) goto DragonKing;
               for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
                 for (s = -2; s <= 2; s += 4) {
                      rt = rf + s * d;
                      ft = ff + s * (1 - d);
                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
-                      if (board[rf+rt>>1][ff+ft>>1] == EmptySquare && gameInfo.variant != VariantSpartan) continue;
+                      if (board[rf+rt>>1][ff+ft>>1] == EmptySquare) continue;
                      if (SameColor(board[rf][ff], board[rt][ft])) continue;
                      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
                  }
-              if(gameInfo.variant == VariantSpartan) // in Spartan Chess restrict range to modern Dababba
-               Wazir(board, flags, rf, ff, callback, closure);
-             else
                Rook(board, flags, rf, ff, callback, closure);
               break;
 
@@ -1142,6 +1149,19 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                    Knight(board, flags, rf, ff, callback, closure);
                break;
 
+            case WhiteTower:
+            case BlackTower:
+                for (d = 0; d <= 1; d++) // Dababba moves
+                  for (s = -2; s <= 2; s += 4) {
+                     rt = rf + s * d;
+                     ft = ff + s * (1 - d);
+                      if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+                     if (SameColor(board[rf][ff], board[rt][ft])) continue;
+                     callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+                 }
+               Wazir(board, flags, rf, ff, callback, closure);
+               break;
+
             /* Shogi Rooks are ordinary Rooks */
             case SHOGI WhiteRook:
             case SHOGI BlackRook:
@@ -1717,6 +1737,8 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant
        }
     }
 
+    if(PieceToChar(king) == '.') return 0; // never in check if the royal piece does not participate
+
     if (rt >= 0) {
        if (enPassant) {
            captured = board[rf][ft];
@@ -1746,10 +1768,10 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant
     /* For compatibility with ICS wild 9, we scan the board in the
        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
        and we test only whether that one is in check. */
+    cl.check = 0;
     for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++)
        for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {
           if (board[cl.rking][cl.fking] == king) {
-             cl.check = 0;
               if(gameInfo.variant == VariantXiangqi) {
                   /* [HGM] In Xiangqi opposing Kings means check as well */
                   int i, dir;
@@ -1784,7 +1806,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant
        board[EP_STATUS] = ep;
     }
 
-    return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
+    return cl.fking < BOARD_RGHT ? cl.check : (gameInfo.variant == VariantAtomic)*1000; // [HGM] atomic: return 1000 if we have no king
 }
 
 int
@@ -1804,7 +1826,7 @@ LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft)
 if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt);
     if(board[rt][ft] != EmptySquare) return ImpossibleMove; // must drop to empty square
     n = PieceToNumber(piece);
-    if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[BOARD_HEIGHT-1-n][0]) != piece)
+    if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[handSize-1-n][0]) != piece)
        && gameInfo.variant != VariantBughouse) // in bughouse we don't check for availability, because ICS doesn't always tell us
         return ImpossibleMove; // piece not available
     if(gameInfo.variant == VariantShogi) { // in Shogi lots of drops are forbidden!
@@ -2145,6 +2167,11 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure)
        }
     } else if(pieceDefs && closure->count > 1 && closure->rtIn >=0) { // [HGM] gen: move is ambiguous under engine-defined rules (and not one-click)
        DisambiguateClosure spare = *closure;
+        if(gameInfo.variant == VariantXiangqi && closure->pieceIn == EmptySquare && closure->ffIn < 0) {
+            closure->ffIn = closure->ftIn; //closure->pieceIn = (flags & 1 ? BlackPawn : WhitePawn); // forward Pawn push has priority
+            Disambiguate(board, flags, closure);
+            return;
+        }
        pieceDefs = FALSE; spare.count = 0;     // See if the (erroneous) built-in rules would resolve that
         GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) &spare, closure->pieceIn);
        if(spare.count == 1) *closure = spare;  // It does, so use those in stead (game from file saved before gen patch?)
@@ -2374,9 +2401,9 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p
             ((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
              (ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
             if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
-             snprintf(out, MOVE_LEN, "O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
+             snprintf(out, MOVE_LEN, "O-O%c%c%c", promoChar ? '/' : 0, ToUpper(promoChar), ff + AAA);
             else
-             snprintf(out, MOVE_LEN, "O-O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
+             snprintf(out, MOVE_LEN, "O-O-O%c%c%c", promoChar ? '/' : 0, ToUpper(promoChar), ff + AAA);
 
            /* This notation is always unambiguous, unless there are
               kings on both the d and e files, with "wild castling"
@@ -2451,8 +2478,15 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p
             *outp++ = ToUpper(promoChar);
         }
         else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating
+            ChessSquare victim = board[rt][ft];
+            if(piece == WhiteRook && victim == WhiteKing ||
+               piece == BlackRook && victim == BlackKing) {
+                strncpy(out, "O-O-O", MOVE_LEN);
+                outp = out + 3 + 2*(ft > ff);
+            }
             *outp++ = '/';
             *outp++ = ToUpper(promoChar);
+            if(out[0] == 'O') *outp++ = ff + AAA;
         }
        *outp = NULLCHAR;
         return cl.kind;