Implement Grand Chess
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 6ccbb1c..89728e1 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 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -126,6 +126,7 @@ ChessSquare CharToPiece(c)
      int c;
 {
      int i;
+     if(c == '.') return EmptySquare;
      for(i=0; i< (int) EmptySquare; i++)
           if(pieceNickName[i] == c) return (ChessSquare) i;
      for(i=0; i< (int) EmptySquare; i++)
@@ -168,20 +169,22 @@ int CompareBoards(board1, board2)
    EP_UNKNOWN if we don't know and want to allow all e.p. captures.
    Promotion moves generated are to Queen only.
 */
-void GenPseudoLegal(board, flags, callback, closure)
+void GenPseudoLegal(board, flags, callback, closure, filter)
      Board board;
      int flags;
      MoveCallback callback;
      VOIDSTAR closure;
+     ChessSquare filter; // [HGM] speed: only do moves with this piece type
 {
     int rf, ff;
     int i, j, d, s, fs, rs, rt, ft, m;
     int epfile = (signed char)board[EP_STATUS]; // [HGM] gamestate: extract ep status from board
-    int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1;
+    int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1;
 
     for (rf = 0; rf < BOARD_HEIGHT; rf++)
       for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
           ChessSquare piece;
+          int rookRange = 1000;
 
          if (flags & F_WHITE_ON_MOVE) {
              if (!WhitePiece(board[rf][ff])) continue;
@@ -191,10 +194,11 @@ void GenPseudoLegal(board, flags, callback, closure)
           m = 0; piece = board[rf][ff];
           if(PieceToChar(piece) == '~')
                  piece = (ChessSquare) ( DEMOTED piece );
+          if(filter != EmptySquare && piece != filter) continue;
           if(gameInfo.variant == VariantShogi)
                  piece = (ChessSquare) ( SHOGI piece );
 
-          switch (piece) {
+          switch ((int)piece) {
             /* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */
            default:
              /* can't happen ([HGM] except for faries...) */
@@ -224,12 +228,12 @@ void GenPseudoLegal(board, flags, callback, closure)
                           rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
                           rf, ff, rf + 1, ff, closure);
              }
-             if (rf == 1 && board[2][ff] == EmptySquare &&
+             if (rf <= (BOARD_HEIGHT>>1)-3 && board[rf+1][ff] == EmptySquare && // [HGM] grand: also on 3rd rank on 10-board
                   gameInfo.variant != VariantShatranj && /* [HGM] */
                   gameInfo.variant != VariantCourier  && /* [HGM] */
-                  board[3][ff] == EmptySquare ) {
+                  board[rf+2][ff] == EmptySquare ) {
                       callback(board, flags, NormalMove,
-                               rf, ff, 3, ff, closure);
+                               rf, ff, rf+2, ff, closure);
              }
              for (s = -1; s <= 1; s += 2) {
                   if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
@@ -239,13 +243,13 @@ void GenPseudoLegal(board, flags, callback, closure)
                               rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
                               rf, ff, rf + 1, ff + s, closure);
                  }
-                 if (rf == BOARD_HEIGHT-4) {
+                 if (rf >= BOARD_HEIGHT+1>>1) {// [HGM] grand: 4th & 5th rank on 10-board
                       if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
-                         (epfile == ff + s || epfile == EP_UNKNOWN) &&
-                          board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&
-                          board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {
+                         (epfile == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 &&
+                          board[rf][ff + s] == BlackPawn &&
+                          board[rf+1][ff + s] == EmptySquare) {
                          callback(board, flags, WhiteCapturesEnPassant,
-                                  rf, ff, 5, ff + s, closure);
+                                  rf, ff, rf+1, ff + s, closure);
                      }
                  }
              }
@@ -274,12 +278,12 @@ void GenPseudoLegal(board, flags, callback, closure)
                           rf <= promoRank ? BlackPromotion : NormalMove,
                           rf, ff, rf - 1, ff, closure);
              }
-             if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
+             if (rf >= (BOARD_HEIGHT+1>>1)+2 && board[rf-1][ff] == EmptySquare && // [HGM] grand
                   gameInfo.variant != VariantShatranj && /* [HGM] */
                   gameInfo.variant != VariantCourier  && /* [HGM] */
-                 board[BOARD_HEIGHT-4][ff] == EmptySquare) {
+                 board[rf-2][ff] == EmptySquare) {
                  callback(board, flags, NormalMove,
-                          rf, ff, BOARD_HEIGHT-4, ff, closure);
+                          rf, ff, rf-2, ff, closure);
              }
              for (s = -1; s <= 1; s += 2) {
                   if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
@@ -289,13 +293,13 @@ void GenPseudoLegal(board, flags, callback, closure)
                               rf <= promoRank ? BlackPromotion : NormalMove,
                               rf, ff, rf - 1, ff + s, closure);
                  }
-                 if (rf == 3) {
+                 if (rf < BOARD_HEIGHT>>1) {
                       if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT &&
-                         (epfile == ff + s || epfile == EP_UNKNOWN) &&
-                         board[3][ff + s] == WhitePawn &&
-                         board[2][ff + s] == EmptySquare) {
+                         (epfile == ff + s || epfile == EP_UNKNOWN) && rf > 2 &&
+                         board[rf][ff + s] == WhitePawn &&
+                         board[rf-1][ff + s] == EmptySquare) {
                          callback(board, flags, BlackCapturesEnPassant,
-                                  rf, ff, 2, ff + s, closure);
+                                  rf, ff, rf-1, ff + s, closure);
                      }
                  }
              }
@@ -418,7 +422,8 @@ void GenPseudoLegal(board, flags, callback, closure)
                           && !SameColor(board[rf][ff], board[rt][ft]))
                                callback(board, flags, NormalMove,
                                         rf, ff, rt, ft, closure);
-                      if(gameInfo.variant != VariantFairy && gameInfo.variant != VariantGreat) continue;
+                      if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier
+                                                             || gameInfo.variant == VariantXiangqi) continue; // classical Alfil
                       rt = rf + rs; // in unknown variant we assume Modern Elephant, which can also do one step
                       ft = ff + fs;
                       if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
@@ -426,6 +431,12 @@ void GenPseudoLegal(board, flags, callback, closure)
                                callback(board, flags, NormalMove,
                                         rf, ff, rt, ft, closure);
                  }
+                if(gameInfo.variant == VariantSpartan)
+                   for(fs = -1; fs <= 1; fs += 2) {
+                      ft = ff + fs;
+                      if (!(ft < BOARD_LEFT || ft >= BOARD_RGHT) && board[rf][ft] == EmptySquare)
+                               callback(board, flags, NormalMove, rf, ff, rf, ft, closure);
+                   }
                 break;
 
             /* Make Dragon-Horse also do Dababba moves outside Shogi, for better disambiguation in variant Fairy */
@@ -507,6 +518,7 @@ void GenPseudoLegal(board, flags, callback, closure)
                      if (SameColor(board[rf][ff], board[rt][ft])) continue;
                      callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
                  }
+              if(gameInfo.variant == VariantSpartan) rookRange = 2; // in Spartan Chess restrict range to modern Dababba
               goto doRook;
               
             /* Shogi Dragon King has to continue as Ferz after Rook moves */
@@ -518,6 +530,7 @@ void GenPseudoLegal(board, flags, callback, closure)
             case WhiteMarshall:
             case BlackMarshall:
               m++;
+              m += (gameInfo.variant == VariantSpartan); // in Spartan Chess Chancellor is used for Dragon King.
 
             /* Shogi Rooks are ordinary Rooks */
             case SHOGI WhiteRook:
@@ -534,7 +547,7 @@ void GenPseudoLegal(board, flags, callback, closure)
                      if (SameColor(board[rf][ff], board[rt][ft])) break;
                      callback(board, flags, NormalMove,
                               rf, ff, rt, ft, closure);
-                     if (board[rt][ft] != EmptySquare) break;
+                     if (board[rt][ft] != EmptySquare || i == rookRange) break;
                  }
                 if(m==1) goto mounted;
                 if(m==2) goto finishSilver;
@@ -701,6 +714,8 @@ typedef struct {
     VOIDSTAR cl;
 } GenLegalClosure;
 
+int rFilter, fFilter; // [HGM] speed: sorry, but I get a bit tired of this closure madness
+
 extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
                                int rf, int ff, int rt, int ft,
                                VOIDSTAR closure));
@@ -714,10 +729,17 @@ void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
 {
     register GenLegalClosure *cl = (GenLegalClosure *) closure;
 
-    if (!(flags & F_IGNORE_CHECK) &&
-       CheckTest(board, flags, rf, ff, rt, ft,
+    if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square
+
+    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
+       check = CheckTest(board, flags, rf, ff, rt, ft,
                  kind == WhiteCapturesEnPassant ||
-                 kind == BlackCapturesEnPassant)) return;
+                 kind == BlackCapturesEnPassant);
+       if(promo) board[rf][ff] = BlackLance;
+      if(check) return;
+    }
     if (flags & F_ATOMIC_CAPTURE) {
       if (board[rt][ft] != EmptySquare ||
          kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
@@ -750,11 +772,12 @@ typedef struct {
    true if castling is not yet ruled out by a move of the king or
    rook.  Return TRUE if the player on move is currently in check and
    F_IGNORE_CHECK is not set.  [HGM] add castlingRights parameter */
-int GenLegal(board, flags, callback, closure)
+int GenLegal(board, flags, callback, closure, filter)
      Board board;
      int flags;
      MoveCallback callback;
      VOIDSTAR closure;
+     ChessSquare filter;
 {
     GenLegalClosure cl;
     int ff, ft, k, left, right, swap;
@@ -763,7 +786,8 @@ int GenLegal(board, flags, callback, closure)
 
     cl.cb = callback;
     cl.cl = closure;
-    GenPseudoLegal(board, flags, GenLegalCallback, (VOIDSTAR) &cl);
+    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;
@@ -985,10 +1009,10 @@ int CheckTest(board, flags, rf, ff, rt, ft, 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;
@@ -999,9 +1023,9 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
                       board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )
                           cl.check++;
               }
-
-             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl);
-             goto undo_move;  /* 2-level break */
+             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl, EmptySquare);
+             if(gameInfo.variant != VariantSpartan || cl.check == 0) // in Spartan Chess go on to test if other King is checked too
+                goto undo_move;  /* 2-level break */
          }
       }
 
@@ -1083,10 +1107,11 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar)
      int flags;
      int rf, ff, rt, ft, promoChar;
 {
-    LegalityTestClosure cl; ChessSquare piece, *castlingRights = board[CASTLING];
+    LegalityTestClosure cl; ChessSquare piece, filterPiece, *castlingRights = board[CASTLING];
 
     if(rf == DROP_RANK) return LegalDrop(board, flags, ff, rt, ft);
-    piece = board[rf][ff];
+    piece = filterPiece = board[rf][ff];
+    if(PieceToChar(piece) == '~') filterPiece = DEMOTED piece; 
 
     if (appData.debugMode) {
         int i;
@@ -1101,11 +1126,12 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar)
 
     cl.rf = rf;
     cl.ff = ff;
-    cl.rt = rt;
-    cl.ft = ft;
+    cl.rt = rFilter = rt; // [HGM] speed: filter on to-square
+    cl.ft = fFilter = ft;
     cl.kind = IllegalMove;
     cl.captures = 0; // [HGM] losers: prepare to count legal captures.
-    GenLegal(board, flags, LegalityTestCallback, (VOIDSTAR) &cl);
+    if(flags & F_MANDATORY_CAPTURE) filterPiece = EmptySquare; // [HGM] speed: do not filter in suicide, to find all captures
+    GenLegal(board, flags, LegalityTestCallback, (VOIDSTAR) &cl, filterPiece);
     if((flags & F_MANDATORY_CAPTURE) && cl.captures && board[rt][ft] == EmptySquare
                && cl.kind != WhiteCapturesEnPassant && cl.kind != BlackCapturesEnPassant)
        return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal
@@ -1156,8 +1182,24 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo
     if (promoChar != NULLCHAR) {
        if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
        if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
-           if(CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(promoChar) : ToLower(promoChar)) == EmptySquare)
+           ChessSquare piece = CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(promoChar) : ToLower(promoChar));
+           if(piece == EmptySquare)
                 cl.kind = ImpossibleMove; // non-existing piece
+           if(gameInfo.variant == VariantSpartan && cl.kind == BlackPromotion ) {
+               if(promoChar != PieceToChar(BlackKing)) {
+                   if(CheckTest(board, flags, rf, ff, rt, ft, FALSE)) cl.kind = IllegalMove; // [HGM] spartan: only promotion to King was possible
+                   if(piece == BlackLance) cl.kind = ImpossibleMove;
+               } else { // promotion to King allowed only if we do not haave two yet
+                   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) cl.kind = IllegalMove;
+               }
+           } else if(piece == WhitePawn && rt == BOARD_HEIGHT-1 ||
+                         piece == BlackPawn && rt == 0) cl.kind = IllegalMove; // cannot stay Pawn on last rank in any variant
+           else if((piece == WhiteUnicorn || piece == BlackUnicorn) && gameInfo.variant == VariantKnightmate)
+             cl.kind = IllegalMove; // promotion to Royal Knight not allowed
+           else if((piece == WhiteKing || piece == BlackKing) && gameInfo.variant != VariantSuicide && gameInfo.variant != VariantGiveaway)
+             cl.kind = IllegalMove; // promotion to King usually not allowed
        } else {
            cl.kind = IllegalMove;
        }
@@ -1216,18 +1258,19 @@ int MateTest(board, flags)
                if(myPieces == 1) return MT_BARE;
     }
     cl.count = 0;
-    inCheck = GenLegal(board, flags, MateTestCallback, (VOIDSTAR) &cl);
+    inCheck = GenLegal(board, flags, MateTestCallback, (VOIDSTAR) &cl, EmptySquare);
     // [HGM] 3check: yet to do!
     if (cl.count > 0) {
        return inCheck ? MT_CHECK : MT_NONE;
     } else {
-        if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper || gameInfo.variant != VariantGreat) { // drop game
+        if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat
+                                                                      && 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
                     if(board[n][holdings] != EmptySquare) {
                         int moveType = LegalDrop(board, flags, board[n][holdings], r, f);
-                        if(moveType == WhiteDrop || moveType == BlackDrop) return MT_CHECK; // we can resolve check by legal drop
+                        if(moveType == WhiteDrop || moveType == BlackDrop) return (inCheck ? MT_CHECK : MT_NONE); // we have legal drop
                     }
         }
        if(gameInfo.variant == VariantSuicide) // [HGM] losers: always stalemate, since no check, but result varies
@@ -1300,11 +1343,13 @@ void Disambiguate(board, flags, closure)
                              closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
                              closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');
     }
-    GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) closure);
+    rFilter = closure->rtIn; // [HGM] speed: only consider moves to given to-square
+    fFilter = closure->ftIn;
+    GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn); // [HGM] speed: only pieces of requested type
     if (closure->count == 0) {
        /* See if it's an illegal move due to check */
         illegal = 1;
-        GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure);
+        GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn);
        if (closure->count == 0) {
            /* No, it's not even that */
     if (appData.debugMode) { int i, j;
@@ -1365,6 +1410,8 @@ void Disambiguate(board, flags, closure)
                 c = PieceToChar(BlackFerz);
             else if(gameInfo.variant == VariantGreat)
                 c = PieceToChar(BlackMan);
+            else if(gameInfo.variant == VariantGrand)
+                   closure->kind = closure->rt != 0 && closure->rt != BOARD_HEIGHT-1 ? NormalMove : AmbiguousMove; // no default in Grand Chess
             else
                 c = PieceToChar(BlackQueen);
         } else if(c == '=') closure->kind = IllegalMove; // no deferral outside Shogi
@@ -1555,18 +1602,19 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
        /* Piece move */
        cl.rf = rf;
        cl.ff = ff;
-       cl.rt = rt;
-       cl.ft = ft;
+       cl.rt = rFilter = rt; // [HGM] speed: filter on to-square
+       cl.ft = fFilter = ft;
        cl.piece = piece;
        cl.kind = IllegalMove;
        cl.rank = cl.file = cl.either = 0;
-        GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+        c = PieceToChar(piece) ;
+        GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece)); // [HGM] speed
 
        if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
            /* Generate pretty moves for moving into check, but
               still return IllegalMove.
            */
-            GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+            GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece));
            if (cl.kind == IllegalMove) break;
            cl.kind = IllegalMove;
        }
@@ -1576,7 +1624,6 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
           else "N1f3" or "N5xf7",
           else "Ng1f3" or "Ng5xf7".
        */
-        c = PieceToChar(piece) ;
         if( c == '~' || c == '+') {
            /* [HGM] print nonexistent piece as its demoted version */
            piece = (ChessSquare) (DEMOTED piece);
@@ -1604,6 +1651,11 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
             /* [HGM] in Shogi non-pawns can promote */
             *outp++ = promoChar; // Don't bother to correct move type, return value is never used!
         }
+        else if (gameInfo.variant != VariantSuper && promoChar && 
+                 (piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn
+            *outp++ = '=';
+            *outp++ = ToUpper(promoChar);
+        }
         else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating
             *outp++ = '/';
             *outp++ = ToUpper(promoChar);
@@ -1667,11 +1719,11 @@ typedef struct {
 int preyStackPointer, chaseStackPointer;
 
 struct {
-char rf, ff, rt, ft;
+unsigned char rf, ff, rt, ft;
 } chaseStack[100];
 
 struct {
-char rank, file;
+unsigned char rank, file;
 } preyStack[100];
 
 
@@ -1763,7 +1815,7 @@ int PerpetualChase(int first, int last)
         if(appData.debugMode) fprintf(debugFP, "judge position %i\n", i);
        chaseStackPointer = 0;   // clear stack that is going to hold possible chases
        // determine all captures possible after the move, and put them on chaseStack
-       GenLegal(boards[i+1], PosFlags(i), AttacksCallback, &cl);
+       GenLegal(boards[i+1], PosFlags(i), AttacksCallback, &cl, EmptySquare);
        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,
@@ -1775,7 +1827,7 @@ 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;
-       GenLegal(boards[i],   PosFlags(i), ExistingAttacksCallback, &cl);
+       GenLegal(boards[i],   PosFlags(i), ExistingAttacksCallback, &cl, EmptySquare);
        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,
@@ -1815,7 +1867,7 @@ 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);
            }
-            GenLegal(boards[i+1], PosFlags(i+1), ProtectedCallback, &cl); // try all moves
+            GenLegal(boards[i+1], PosFlags(i+1), ProtectedCallback, &cl, EmptySquare); // try all moves
            // 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;