Fix Seirawan gating at Rook square in PGN castling moves
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index a5ec955..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);
@@ -934,11 +936,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                if(gameInfo.variant == VariantShogi) goto WhiteGold;
             case SHOGI (PROMO BlackPawn):
                if(gameInfo.variant == VariantShogi) goto BlackGold;
+            case SHOGI WhiteAxe:
+            case SHOGI BlackAxe:
                SlideVertical(board, flags, rf, ff, callback, closure);
                break;
 
             case SHOGI (PROMO WhiteKnight):
                if(gameInfo.variant == VariantShogi) goto WhiteGold;
+            case SHOGI WhiteClaw:
             case SHOGI BlackDrunk:
             case SHOGI BlackAlfil:
                Ferz(board, flags, rf, ff, callback, closure);
@@ -948,6 +953,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
 
             case SHOGI (PROMO BlackKnight):
                if(gameInfo.variant == VariantShogi) goto BlackGold;
+            case SHOGI BlackClaw:
             case SHOGI WhiteDrunk:
             case SHOGI WhiteAlfil:
                Ferz(board, flags, rf, ff, callback, closure);
@@ -982,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;
 
@@ -1101,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;
 
@@ -1138,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:
@@ -1276,8 +1300,8 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
               }
               break;
 
-            case SHOGI WhiteFalcon:
-            case SHOGI BlackFalcon:
+            case SHOGI WhiteDagger:
+            case SHOGI BlackDagger:
             case SHOGI WhitePDagger:
             case SHOGI BlackPDagger:
                SlideSideways(board, flags, rf, ff, callback, closure);
@@ -1293,24 +1317,26 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                if(gameInfo.variant == VariantShogi) goto WhiteGold;
             case SHOGI (PROMO BlackFerz):
                if(gameInfo.variant == VariantShogi) goto BlackGold;
+            case SHOGI WhiteSword:
+            case SHOGI BlackSword:
             case SHOGI WhitePSword:
             case SHOGI BlackPSword:
                SlideVertical(board, flags, rf, ff, callback, closure);
                StepSideways(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteUnicorn:
-            case SHOGI BlackUnicorn:
+            case SHOGI WhiteCat:
+            case SHOGI BlackCat:
                Ferz(board, flags, rf, ff, callback, closure);
                StepVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteMan:
+            case SHOGI WhiteCopper:
                StepDiagForward(board, flags, rf, ff, callback, closure);
                StepVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackMan:
+            case SHOGI BlackCopper:
                StepDiagBackward(board, flags, rf, ff, callback, closure);
                StepVertical(board, flags, rf, ff, callback, closure);
                break;
@@ -1327,7 +1353,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideVertical(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteCat:
+            case SHOGI WhiteUnicorn:
                Sting(board, flags, rf, ff, 1, 0, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
                if(killX >= 0) break;
@@ -1336,7 +1362,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideBackward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackCat:
+            case SHOGI BlackUnicorn:
                Sting(board, flags, rf, ff, -1, 0, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
                if(killX >= 0) break;
@@ -1345,7 +1371,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideForward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI WhiteDagger:
+            case SHOGI WhiteFalcon:
                Sting(board, flags, rf, ff, 1,  1, callback, closure);
                Sting(board, flags, rf, ff, 1, -1, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
@@ -1354,7 +1380,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure,
                SlideDiagBackward(board, flags, rf, ff, callback, closure);
                break;
 
-            case SHOGI BlackDagger:
+            case SHOGI BlackFalcon:
                Sting(board, flags, rf, ff, -1,  1, callback, closure);
                Sting(board, flags, rf, ff, -1, -1, callback, closure);
                callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
@@ -1711,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];
@@ -1740,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;
@@ -1778,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
@@ -1798,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!
@@ -2139,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?)
@@ -2368,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"
@@ -2445,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;