Updated copyright notice to 2012
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index a8f55b6..12eed07 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -5,7 +5,7 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -717,6 +717,7 @@ typedef struct {
 } GenLegalClosure;
 
 int rFilter, fFilter; // [HGM] speed: sorry, but I get a bit tired of this closure madness
+Board xqCheckers, nullBoard;
 
 extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
                                int rf, int ff, int rt, int ft,
@@ -735,7 +736,15 @@ void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
 
     if (!(flags & F_IGNORE_CHECK) ) {
       int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion);
-      if(promo) board[rf][ff] = BlackKing; // [HGM] spartan: promote to King before check-test
+      if(promo) {
+           int r, f, kings=0;
+           for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT;       f++)
+               kings += (board[r][f] == BlackKing);
+           if(kings >= 2)
+             promo = 0;
+           else
+               board[rf][ff] = BlackKing; // [HGM] spartan: promote to King before check-test
+       }
        check = CheckTest(board, flags, rf, ff, rt, ft,
                  kind == WhiteCapturesEnPassant ||
                  kind == BlackCapturesEnPassant);
@@ -785,14 +794,15 @@ int GenLegal(board, flags, callback, closure, filter)
     int ff, ft, k, left, right, swap;
     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
     ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING];
+    int inCheck = !ignoreCheck && CheckTest(board, flags, -1, -1, -1, -1, FALSE); // kludge alert: this would mark pre-existing checkers if status==1
 
     cl.cb = callback;
     cl.cl = closure;
+    xqCheckers[EP_STATUS] *= 2; // quasi: if previous CheckTest has been marking, we now set flag for suspending same checkers
     if(filter == EmptySquare) rFilter = fFilter = -1; // [HGM] speed: do not filter on square if we do not filter on piece
     GenPseudoLegal(board, flags, GenLegalCallback, (VOIDSTAR) &cl, filter);
 
-    if (!ignoreCheck &&
-       CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
+    if (inCheck) return TRUE;
 
     /* Generate castling moves */
     if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */
@@ -971,7 +981,11 @@ void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
 {
     register CheckTestClosure *cl = (CheckTestClosure *) closure;
 
-    if (rt == cl->rking && ft == cl->fking) cl->check++;
+    if (rt == cl->rking && ft == cl->fking) {
+       if(xqCheckers[EP_STATUS] >= 2 && xqCheckers[rf][ff]) return; // checker is piece with suspended checking power
+       cl->check++;
+       xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1)
+    }
 }
 
 
@@ -997,16 +1011,18 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
     if(gameInfo.variant == VariantKnightmate)
         king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
 
-    if (rf >= 0) {
+    if (rt >= 0) {
        if (enPassant) {
            captured = board[rf][ft];
            board[rf][ft] = EmptySquare;
        } else {
            captured = board[rt][ft];
        }
-       board[rt][ft] = board[rf][ff];
-       board[rf][ff] = EmptySquare;
-    } else board[rt][ft] = ff; // [HGM] drop
+       if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop
+           board[rt][ft] = board[rf][ff];
+           board[rf][ff] = EmptySquare;
+       }
+    }
 
     /* For compatibility with ICS wild 9, we scan the board in the
        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
@@ -1033,15 +1049,16 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
 
   undo_move:
 
-    if (rf >= 0) {
-       board[rf][ff] = board[rt][ft];
+    if (rt >= 0) {
+       if(rf != DROP_RANK) // [HGM] drop
+           board[rf][ff] = board[rt][ft];
        if (enPassant) {
            board[rf][ft] = captured;
            board[rt][ft] = EmptySquare;
        } else {
            board[rt][ft] = captured;
        }
-    } else board[rt][ft] = EmptySquare; // [HGM] drop
+    }
 
     return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
 }
@@ -1267,7 +1284,7 @@ int MateTest(board, flags)
        return inCheck ? MT_CHECK : MT_NONE;
     } else {
         if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat
-                                                                      && gameInfo.variant != VariantGrand) { // drop game
+                                 && gameInfo.variant != VariantSChess && gameInfo.variant != VariantGrand) { // drop game
             int r, f, n, holdings = flags & F_WHITE_ON_MOVE ? BOARD_WIDTH-1 : 0;
             for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) if(board[r][f] == EmptySquare) // all empty squares
                 for(n=0; n<BOARD_HEIGHT; n++) // all pieces in hand
@@ -1841,7 +1858,9 @@ int PerpetualChase(int first, int last)
        cl.ff = moveList[i][0]-AAA+BOARD_LEFT;
        cl.rt = moveList[i][3]-ONE;
        cl.ft = moveList[i][2]-AAA+BOARD_LEFT;
+       CopyBoard(xqCheckers, nullBoard); xqCheckers[EP_STATUS] = 1; // giant kludge to make GenLegal ignore pre-existing checks
        GenLegal(boards[i],   PosFlags(i), ExistingAttacksCallback, &cl, EmptySquare);
+       xqCheckers[EP_STATUS] = 0; // disable the generation of quasi-legal moves again
        if(appData.debugMode) { int n;
            for(n=0; n<chaseStackPointer; n++)
                 fprintf(debugFP, "%c%c%c%c ", chaseStack[n].ff+AAA, chaseStack[n].rf+ONE,
@@ -1870,6 +1889,8 @@ int PerpetualChase(int first, int last)
            }
 
            // the attack is on a lower piece, or on a pinned or blocked equal one
+           CopyBoard(xqCheckers, nullBoard); xqCheckers[EP_STATUS] = 1;
+           CheckTest(boards[i+1], PosFlags(i+1), -1, -1, -1, -1, FALSE); // if we deliver check with our move, the checkers get marked
             // test if the victim is protected by a true protector. First make the capture.
            captured = boards[i+1][chaseStack[j].rt][chaseStack[j].ft];
            boards[i+1][chaseStack[j].rt][chaseStack[j].ft] = boards[i+1][chaseStack[j].rf][chaseStack[j].ff];
@@ -1881,7 +1902,9 @@ int PerpetualChase(int first, int last)
            if(appData.debugMode) {
                fprintf(debugFP, "test if we can recapture %c%c\n", cl.ft+AAA, cl.rt+ONE);
            }
+           xqCheckers[EP_STATUS] = 2; // causes GenLegal to ignore the checks we delivered with the move, in real life evaded before we captured
             GenLegal(boards[i+1], PosFlags(i+1), ProtectedCallback, &cl, EmptySquare); // try all moves
+           xqCheckers[EP_STATUS] = 0; // disable quasi-legal moves again
            // unmake the capture
            boards[i+1][chaseStack[j].rf][chaseStack[j].ff] = boards[i+1][chaseStack[j].rt][chaseStack[j].ft];
             boards[i+1][chaseStack[j].rt][chaseStack[j].ft] = captured;
@@ -1935,5 +1958,6 @@ int PerpetualChase(int first, int last)
             }
         }
     }
-    return preyStackPointer; // if any piece was left on preyStack, it has been perpetually chased
+    return preyStackPointer ? 256*(preyStack[preyStackPointer].file - BOARD_LEFT + AAA) + (preyStack[preyStackPointer].rank + ONE)
+                               : 0; // if any piece was left on preyStack, it has been perpetually chased,and we return the
 }