Remove promotion-piece encoding from ChessMove type
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index 970393f..56bd1da 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -1,11 +1,13 @@
 /*
  * moves.c - Move generation and checking
- * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $
  *
  * Copyright 1991 by Digital Equipment Corporation, Maynard,
- * Massachusetts.  Enhancements Copyright
- * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
- * Foundation, Inc.
+ * Massachusetts.
+ *
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
+ * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ *
+ * Enhancements Copyright 2005 Alessandro Scotti
  *
  * The following terms apply to Digital Equipment Corporation's copyright
  * interest in XBoard:
@@ -67,7 +69,7 @@ int BlackPiece P((ChessSquare));
 int SameColor P((ChessSquare, ChessSquare));
 int PosFlags(int index);
 
-extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */
+extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */
 
 
 int WhitePiece(piece)
@@ -95,53 +97,13 @@ int SameColor(piece1, piece2)
             (int) piece2 <  (int) EmptySquare);
 }
 
-ChessSquare PromoPiece(moveType)
-     ChessMove moveType;
-{
-    switch (moveType) {
-      default:
-       return EmptySquare;
-      case WhitePromotionQueen:
-       return WhiteQueen;
-      case BlackPromotionQueen:
-       return BlackQueen;
-      case WhitePromotionRook:
-       return WhiteRook;
-      case BlackPromotionRook:
-       return BlackRook;
-      case WhitePromotionBishop:
-       return WhiteBishop;
-      case BlackPromotionBishop:
-       return BlackBishop;
-      case WhitePromotionKnight:
-       return WhiteKnight;
-      case BlackPromotionKnight:
-       return BlackKnight;
-      case WhitePromotionKing:
-       return WhiteKing;
-      case BlackPromotionKing:
-       return BlackKing;
-      case WhitePromotionChancellor:
-        return WhiteMarshall;
-      case BlackPromotionChancellor:
-        return BlackMarshall;
-      case WhitePromotionArchbishop:
-        return WhiteAngel;
-      case BlackPromotionArchbishop:
-        return BlackAngel;
-      case WhitePromotionCentaur:
-        return WhiteSilver;
-      case BlackPromotionCentaur:
-        return BlackSilver;
-    }
-}
-
 char pieceToChar[] = {
                         'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', 
-                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K',
+                        'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 'S', 'U', 'K',
                         'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', 
                         'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', 
                         'x' };
+char pieceNickName[EmptySquare];
 
 char PieceToChar(p)
      ChessSquare p;
@@ -165,58 +127,12 @@ ChessSquare CharToPiece(c)
 {
      int i;
      for(i=0; i< (int) EmptySquare; i++)
+          if(pieceNickName[i] == c) return (ChessSquare) i;
+     for(i=0; i< (int) EmptySquare; i++)
           if(pieceToChar[i] == c) return (ChessSquare) i;
      return EmptySquare;
 }
 
-ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
-     int whiteOnMove;
-     int promoChar;
-{      /* [HGM] made dependent on CharToPiece to alow alternate piece letters */
-       ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) );
-
-
-       if(promoChar == NULLCHAR) return NormalMove;
-
-       switch(piece) {
-               case WhiteQueen:
-                       return WhitePromotionQueen;
-               case WhiteRook:
-                       return WhitePromotionRook;
-               case WhiteBishop:
-                       return WhitePromotionBishop;
-               case WhiteKnight:
-                       return WhitePromotionKnight;
-               case WhiteKing:
-                       return WhitePromotionKing;
-               case WhiteAngel:
-                       return WhitePromotionArchbishop;
-               case WhiteMarshall:
-                       return WhitePromotionChancellor;
-               case WhiteSilver:
-                       return WhitePromotionCentaur;
-               case BlackQueen:
-                       return BlackPromotionQueen;
-               case BlackRook:
-                       return BlackPromotionRook;
-               case BlackBishop:
-                       return BlackPromotionBishop;
-               case BlackKnight:
-                       return BlackPromotionKnight;
-               case BlackKing:
-                       return BlackPromotionKing;
-               case BlackAngel:
-                       return BlackPromotionArchbishop;
-               case BlackMarshall:
-                       return BlackPromotionChancellor;
-               case BlackSilver:
-                       return BlackPromotionCentaur;
-               default:
-                       // not all promotion implemented yet! Take Queen for those we don't know.
-                       return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen);
-       }
-}
-
 void CopyBoard(to, from)
      Board to, from;
 {
@@ -225,6 +141,9 @@ void CopyBoard(to, from)
     for (i = 0; i < BOARD_HEIGHT; i++)
       for (j = 0; j < BOARD_WIDTH; j++)
        to[i][j] = from[i][j];
+    for (j = 0; j < BOARD_FILES-1; j++) // [HGM] gamestate: copy castling rights and ep status
+       to[CASTLING][j] = from[CASTLING][j];
+    to[HOLDINGS_SET] = 0; // flag used in ICS play
 }
 
 int CompareBoards(board1, board2)
@@ -249,15 +168,16 @@ 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, epfile, callback, closure)
+void GenPseudoLegal(board, flags, callback, closure)
      Board board;
      int flags;
-     int epfile;
      MoveCallback callback;
      VOIDSTAR closure;
 {
     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;
 
     for (rf = 0; rf < BOARD_HEIGHT; rf++) 
       for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) {
@@ -301,7 +221,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               }
               if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {
                  callback(board, flags,
-                          rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
+                          rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
                           rf, ff, rf + 1, ff, closure);
              }
              if (rf == 1 && board[2][ff] == EmptySquare &&
@@ -316,7 +236,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      ((flags & F_KRIEGSPIEL_CAPTURE) ||
                       BlackPiece(board[rf + 1][ff + s]))) {
                      callback(board, flags, 
-                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,
+                              rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
                               rf, ff, rf + 1, ff + s, closure);
                  }
                  if (rf == BOARD_HEIGHT-4) {
@@ -351,7 +271,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               }
              if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
                  callback(board, flags, 
-                          rf == 1 ? BlackPromotionQueen : NormalMove,
+                          rf <= promoRank ? BlackPromotion : NormalMove,
                           rf, ff, rf - 1, ff, closure);
              }
              if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&
@@ -366,7 +286,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      ((flags & F_KRIEGSPIEL_CAPTURE) ||
                       WhitePiece(board[rf - 1][ff + s]))) {
                      callback(board, flags, 
-                              rf == 1 ? BlackPromotionQueen : NormalMove,
+                              rf <= promoRank ? BlackPromotion : NormalMove,
                               rf, ff, rf - 1, ff + s, closure);
                  }
                  if (rf == 3) {
@@ -584,7 +504,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                      if (board[rt][ft] != EmptySquare) break;
                  }
                 if(m==1) goto mounted;
-                if(m==2) goto finishGold;
+                if(m==2) goto finishSilver;
              break;
 
            case WhiteQueen:
@@ -606,6 +526,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
 
             /* Shogi Pawn and Silver General: first the Pawn move,    */
             /* then the General continues like a Ferz                 */
+            case WhiteMan:
+                if(gameInfo.variant != VariantMakruk) goto commoner;
             case SHOGI WhitePawn:
             case SHOGI WhiteFerz:
                   if (rf < BOARD_HEIGHT-1 &&
@@ -615,6 +537,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
               if(piece != SHOGI WhitePawn) goto finishSilver;
               break;
 
+            case BlackMan:
+                if(gameInfo.variant != VariantMakruk) goto commoner;
             case SHOGI BlackPawn:
             case SHOGI BlackFerz:
                   if (rf > 0 &&
@@ -642,8 +566,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
            case WhiteSilver:
            case BlackSilver:
                m++; // [HGM] superchess: use for Centaur
-            case WhiteMan:
-            case BlackMan:
+            commoner:
             case SHOGI WhiteKing:
             case SHOGI BlackKing:
            case WhiteKing:
@@ -678,6 +601,14 @@ void GenPseudoLegal(board, flags, epfile, callback, closure)
                     }
                  }
              break;
+           case WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere
+           case BlackFalcon:
+           case WhiteCobra:
+           case BlackCobra:
+           case WhiteLance:
+           case BlackLance:
+             callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
+             break;
 
          }
       }
@@ -738,22 +669,20 @@ 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, epfile, castlingRights, callback, closure)
+int GenLegal(board, flags, callback, closure)
      Board board;
      int flags;
-     int epfile;
-     char castlingRights[];
      MoveCallback callback;
      VOIDSTAR closure;
 {
     GenLegalClosure cl;
     int ff, ft, k, left, right;
     int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
-    ChessSquare wKing = WhiteKing, bKing = BlackKing;
+    ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING];
 
     cl.cb = callback;
     cl.cl = closure;
-    GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);
+    GenPseudoLegal(board, flags, GenLegalCallback, (VOIDSTAR) &cl);
 
     if (!ignoreCheck &&
        CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
@@ -772,7 +701,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             board[0][BOARD_RGHT-3] == EmptySquare &&
             board[0][BOARD_RGHT-2] == EmptySquare &&
             board[0][BOARD_RGHT-1] == WhiteRook &&
-            castlingRights[0] >= 0 && /* [HGM] check rights */
+            castlingRights[0] != NoRights && /* [HGM] check rights */
             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
             (ignoreCheck ||                             
             (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&
@@ -792,7 +721,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             board[0][BOARD_LEFT+2] == EmptySquare &&
             board[0][BOARD_LEFT+1] == EmptySquare &&
             board[0][BOARD_LEFT+0] == WhiteRook &&
-            castlingRights[1] >= 0 && /* [HGM] check rights */
+            castlingRights[1] != NoRights && /* [HGM] check rights */
             ( castlingRights[2] == ff || castlingRights[6] == ff ) &&
            (ignoreCheck ||
             (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&
@@ -811,7 +740,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare &&
             board[BOARD_HEIGHT-1][BOARD_RGHT-2] == EmptySquare &&
             board[BOARD_HEIGHT-1][BOARD_RGHT-1] == BlackRook &&
-            castlingRights[3] >= 0 && /* [HGM] check rights */
+            castlingRights[3] != NoRights && /* [HGM] check rights */
             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
            (ignoreCheck ||
             (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&
@@ -831,7 +760,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare &&
             board[BOARD_HEIGHT-1][BOARD_LEFT+1] == EmptySquare &&
             board[BOARD_HEIGHT-1][BOARD_LEFT+0] == BlackRook &&
-            castlingRights[4] >= 0 && /* [HGM] check rights */
+            castlingRights[4] != NoRights && /* [HGM] check rights */
             ( castlingRights[5] == ff || castlingRights[7] == ff ) &&
            (ignoreCheck ||
             (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&
@@ -844,7 +773,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
        }
     }
 
-  if(gameInfo.variant == VariantFischeRandom) {
+  if(flags & F_FRC_TYPE_CASTLING) {
 
     /* generate all potential FRC castling moves (KxR), ignoring flags */
     /* [HGM] test if the Rooks we find have castling rights */
@@ -852,7 +781,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
 
     if ((flags & F_WHITE_ON_MOVE) != 0) {
         ff = castlingRights[2]; /* King file if we have any rights */
-        if(ff > 0 && board[0][ff] == WhiteKing) {
+        if(ff != NoRights && board[0][ff] == WhiteKing) {
     if (appData.debugMode) {
         fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n",
                 castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]);
@@ -861,49 +790,49 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure)
             left  = ff+1;
             right = BOARD_RGHT-2;
             if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
-                if(k != ft && board[0][k] != EmptySquare) ft = -1;
-            for(k=left; k<right && ft >= 0; k++) /* then if not checked */
-                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;
-            if(ft >= 0 && board[0][ft] == WhiteRook)
+            for(k=left; k<=right && ft != NoRights; k++) /* first test if blocked */
+                if(k != ft && board[0][k] != EmptySquare) ft = NoRights;
+            for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
+            if(ft != NoRights && board[0][ft] == WhiteRook)
                 callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);
 
             ft = castlingRights[1]; /* Rook file if we have A-side rights */
             left  = BOARD_LEFT+2;
             right = ff-1;
             if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
-                if(k != ft && board[0][k] != EmptySquare) ft = -1;
+            for(k=left; k<=right && ft != NoRights; k++) /* first test if blocked */
+                if(k != ft && board[0][k] != EmptySquare) ft = NoRights;
             if(ff > BOARD_LEFT+2) 
-            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */
-                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1;
-            if(ft >= 0 && board[0][ft] == WhiteRook)
+            for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
+            if(ft != NoRights && board[0][ft] == WhiteRook)
                 callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);
         }
     } else {
         ff = castlingRights[5]; /* King file if we have any rights */
-        if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) {
+        if(ff != NoRights && board[BOARD_HEIGHT-1][ff] == BlackKing) {
             ft = castlingRights[3]; /* Rook file if we have H-side rights */
             left  = ff+1;
             right = BOARD_RGHT-2;
             if(ff == BOARD_RGHT-2) left = right = ff-1;    /* special case */
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
-                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;
-            for(k=left; k<right && ft >= 0; k++) /* then if not checked */
-                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;
-            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)
+            for(k=left; k<=right && ft != NoRights; k++) /* first test if blocked */
+                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = NoRights;
+            for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
+            if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
                 callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
 
             ft = castlingRights[4]; /* Rook file if we have A-side rights */
             left  = BOARD_LEFT+2;
             right = ff-1;
             if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; }
-            for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */
-                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1;
+            for(k=left; k<=right && ft != NoRights; k++) /* first test if blocked */
+                if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = NoRights;
             if(ff > BOARD_LEFT+2) 
-            for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */
-                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1;
-            if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook)
+            for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
+                if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
+            if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
                 callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
         }
     }
@@ -969,7 +898,7 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
        }
        board[rt][ft] = board[rf][ff];
        board[rf][ff] = EmptySquare;
-    }
+    } else board[rt][ft] = ff; // [HGM] drop
 
     /* For compatibility with ICS wild 9, we scan the board in the
        order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,
@@ -989,8 +918,7 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
                           cl.check++;
               }
 
-             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,
-                            CheckTestCallback, (VOIDSTAR) &cl);
+             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl);
              goto undo_move;  /* 2-level break */
          }
       }
@@ -1005,11 +933,44 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
        } else {
            board[rt][ft] = captured;
        }
-    }
+    } else board[rt][ft] = EmptySquare; // [HGM] drop
 
-    return cl.check;
+    return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king
 }
 
+ChessMove LegalDrop(board, flags, piece, rt, ft)
+     Board board;
+     int flags;
+     ChessSquare piece;
+     int rt, ft;
+{   // [HGM] put drop legality testing in separate routine for clarity
+    int n;
+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)
+        return ImpossibleMove; // piece not available
+    if(gameInfo.variant == VariantShogi) { // in Shogi lots of drops are forbidden!
+        if((piece == WhitePawn || piece == WhiteQueen) && rt == BOARD_HEIGHT-1 ||
+           (piece == BlackPawn || piece == BlackQueen) && rt == 0 ||
+            piece == WhiteKnight && rt > BOARD_HEIGHT-3 ||
+            piece == BlackKnight && rt < 2 ) return IllegalMove; // e.g. where dropped piece has no moves
+        if(piece == WhitePawn || piece == BlackPawn) {
+            int r;
+            for(r=1; r<BOARD_HEIGHT-1; r++)
+                if(board[r][ft] == piece) return IllegalMove; // or there already is a Pawn in file
+            // should still test if we mate with this Pawn
+        }
+    } else {
+        if( (piece == WhitePawn || piece == BlackPawn) &&
+            (rt == 0 || rt == BOARD_HEIGHT -1 ) )
+            return IllegalMove; /* no pawn drops on 1st/8th */
+    }
+if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt);
+    if (!(flags & F_IGNORE_CHECK) &&
+       CheckTest(board, flags, DROP_RANK, piece, rt, ft, FALSE) ) return IllegalMove;
+    return flags & F_WHITE_ON_MOVE ? WhiteDrop : BlackDrop;
+}
 
 extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
                                    int rf, int ff, int rt, int ft,
@@ -1033,13 +994,15 @@ void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
       cl->kind = kind;
 }
 
-ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)
+ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar)
      Board board;
-     int flags, epfile;
+     int flags;
      int rf, ff, rt, ft, promoChar;
-     char castlingRights[];
 {
-    LegalityTestClosure cl; ChessSquare piece = board[rf][ff];
+    LegalityTestClosure cl; ChessSquare piece, *castlingRights = board[CASTLING];
+
+    if(rf == DROP_RANK) return LegalDrop(board, flags, ff, rt, ft);
+    piece = board[rf][ff];
     
     if (appData.debugMode) {
         int i;
@@ -1051,7 +1014,7 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro
     if(piece == WhiteFalcon || piece == BlackFalcon ||
        piece == WhiteCobra  || piece == BlackCobra  ||
        piece == WhiteLance  || piece == BlackLance)
-        return NormalMove;
+        return CheckTest(board, flags, rf, ff, rt, ft, FALSE) ? IllegalMove : NormalMove;
 
     cl.rf = rf;
     cl.ff = ff;
@@ -1059,55 +1022,52 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro
     cl.ft = ft;
     cl.kind = IllegalMove;
     cl.captures = 0; // [HGM] losers: prepare to count legal captures.
-    GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);
+    GenLegal(board, flags, LegalityTestCallback, (VOIDSTAR) &cl);
     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
 
+    if(promoChar == 'x') promoChar = NULLCHAR; // [HGM] is this ever the case?
     if(gameInfo.variant == VariantShogi) {
         /* [HGM] Shogi promotions. '=' means defer */
         if(rf != DROP_RANK && cl.kind == NormalMove) {
             ChessSquare piece = board[rf][ff];
 
             if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */
-            if(promoChar != NULLCHAR && promoChar != 'x' &&
-               promoChar != '+' && promoChar != '=' &&
+            if(promoChar != NULLCHAR && promoChar != '+' && promoChar != '=' &&
                ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) )
                     cl.kind = IllegalMove;
             else if(flags & F_WHITE_ON_MOVE) {
                 if( (int) piece < (int) WhiteWazir &&
-                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {
+                     (rf >= BOARD_HEIGHT*2/3 || rt >= BOARD_HEIGHT*2/3) ) {
                     if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
-                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;
+                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion;
                     else /* promotion optional, default is promote */
-                             cl.kind = promoChar == '=' ? NormalMove  : WhitePromotionQueen;
+                             cl.kind = promoChar == '=' ? WhiteNonPromotion : WhitePromotion;
                    
                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
                                             NormalMove : IllegalMove;
             } else {
-                if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {
+                if( (int) piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) {
                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */
-                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;
+                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion;
                     else /* promotion optional, default is promote */
-                             cl.kind = promoChar == '=' ? NormalMove  : BlackPromotionQueen;
+                             cl.kind = promoChar == '=' ? BlackNonPromotion : BlackPromotion;
 
-                } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
-                                            NormalMove : IllegalMove;
+                } else cl.kind = (promoChar == NULLCHAR || promoChar == '=') ? NormalMove : IllegalMove;
             }
         }
     } else
-    if (promoChar != NULLCHAR && promoChar != 'x') {
+    if (promoChar != NULLCHAR) {
        if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
-       if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
-           cl.kind = 
-             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);
+       if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
+           if(CharToPiece(promoChar) == EmptySquare) cl.kind = ImpossibleMove; // non-existing piece
        } else {
            cl.kind = IllegalMove;
        }
     }
-    /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */
     return cl.kind;
 }
 
@@ -1132,19 +1092,56 @@ void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
 }
 
 /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
-int MateTest(board, flags, epfile, castlingRights)
+int MateTest(board, flags)
      Board board;
-     int flags, epfile;
-     char castlingRights[];
+     int flags;
 {
     MateTestClosure cl;
-    int inCheck;
+    int inCheck, r, f, myPieces=0, hisPieces=0, nrKing=0;
+    ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
 
+    for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) { 
+        // [HGM] losers: Count pieces and kings, to detect other unorthodox winning conditions
+       nrKing += (board[r][f] == king);   // stm has king
+        if( board[r][f] != EmptySquare ) {
+           if((int)board[r][f] <= (int)king && (int)board[r][f] >= (int)king - (int)WhiteKing + (int)WhitePawn)
+                myPieces++;
+           else hisPieces++;
+       }
+    }
+    if(appData.debugMode) fprintf(debugFP, "MateTest: K=%d, my=%d, his=%d\n", nrKing, myPieces, hisPieces);
+    switch(gameInfo.variant) { // [HGM] losers: extinction wins
+       case VariantShatranj:
+               if(hisPieces == 1) return myPieces > 1 ? MT_BARE : MT_DRAW;
+       default:
+               break;
+       case VariantAtomic:
+               if(nrKing == 0) return MT_NOKING;
+               break;
+       case VariantLosers:
+               if(myPieces == 1) return MT_BARE;
+    }
     cl.count = 0;
-    inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);
+    inCheck = GenLegal(board, flags, MateTestCallback, (VOIDSTAR) &cl);
+    // [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
+            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(gameInfo.variant == VariantSuicide) // [HGM] losers: always stalemate, since no check, but result varies
+               return myPieces == hisPieces ? MT_STALEMATE :
+                                       myPieces > hisPieces ? MT_STAINMATE : MT_STEALMATE;
+       else if(gameInfo.variant == VariantLosers) return inCheck ? MT_TRICKMATE : MT_STEALMATE;
+       else if(gameInfo.variant == VariantGiveaway) return MT_STEALMATE; // no check exists, stalemated = win
+                                           
         return inCheck ? MT_CHECKMATE 
                       : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj) ? 
                          MT_STAINMATE : MT_STALEMATE;
@@ -1164,6 +1161,13 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
      VOIDSTAR closure;
 {
     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
+    int wildCard = FALSE; ChessSquare piece = board[rf][ff];
+
+    // [HGM] wild: for wild-card pieces rt and rf are dummies
+    if(piece == WhiteFalcon || piece == BlackFalcon ||
+       piece == WhiteCobra  || piece == BlackCobra  ||
+       piece == WhiteLance  || piece == BlackLance)
+        wildCard = TRUE;
 
     if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]
          || PieceToChar(board[rf][ff]) == '~'
@@ -1171,26 +1175,31 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
                                                                       ) &&
        (cl->rfIn == -1 || cl->rfIn == rf) &&
        (cl->ffIn == -1 || cl->ffIn == ff) &&
-       (cl->rtIn == -1 || cl->rtIn == rt) &&
-       (cl->ftIn == -1 || cl->ftIn == ft)) {
+       (cl->rtIn == -1 || cl->rtIn == rt || wildCard) &&
+       (cl->ftIn == -1 || cl->ftIn == ft || wildCard)) {
 
        cl->count++;
-        cl->piece = board[rf][ff];
-       cl->rf = rf;
-       cl->ff = ff;
-       cl->rt = rt;
-       cl->ft = ft;
-       cl->kind = kind;
+       if(cl->count == 1 || board[rt][ft] != EmptySquare) {
+         // [HGM] oneclick: if multiple moves, be sure we remember capture
+         cl->piece = board[rf][ff];
+         cl->rf = rf;
+         cl->ff = ff;
+         cl->rt = wildCard ? cl->rtIn : rt;
+         cl->ft = wildCard ? cl->ftIn : ft;
+         cl->kind = kind;
+       }
+       cl->captures += (board[cl->rt][cl->ft] != EmptySquare); // [HGM] oneclick: count captures
     }
 }
 
-void Disambiguate(board, flags, epfile, closure)
+void Disambiguate(board, flags, closure)
      Board board;
-     int flags, epfile;
+     int flags;
      DisambiguateClosure *closure;
 {
     int illegal = 0; char c = closure->promoCharIn;
-    closure->count = 0;
+
+    closure->count = closure->captures = 0;
     closure->rf = closure->ff = closure->rt = closure->ft = 0;
     closure->kind = ImpossibleMove;
     if (appData.debugMode) {
@@ -1198,12 +1207,11 @@ void Disambiguate(board, flags, epfile, closure)
                              closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
                              closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');
     }
-    GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);
+    GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) closure);
     if (closure->count == 0) {
        /* See if it's an illegal move due to check */
         illegal = 1;
-        GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,
-                (VOIDSTAR) closure);   
+        GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure);       
        if (closure->count == 0) {
            /* No, it's not even that */
     if (appData.debugMode) { int i, j;
@@ -1217,73 +1225,41 @@ void Disambiguate(board, flags, epfile, closure)
        }
     }
 
+    if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?)
     if(gameInfo.variant == VariantShogi) {
-        /* [HGM] Shogi promotions. '=' means defer */
+        /* [HGM] Shogi promotions. On input, '=' means defer, NULL promote. Afterwards, c is set to '+' for promotions, NULL other */
         if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) {
             ChessSquare piece = closure->piece;
-#if 0
-    if (appData.debugMode) {
-        fprintf(debugFP, "Disambiguate A:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
-                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
-                          closure->promoCharIn,closure->promoCharIn);
-    }
-#endif
-            if(c != NULLCHAR && c != 'x' && c != '+' && c != '=' &&
+            if(c != NULLCHAR && c != '+' && c != '=' &&
                ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(c) ) 
-                    closure->kind = IllegalMove;
+                    closure->kind = IllegalMove; // the only allowed cases are '+', '=' and the promoted partner.
             else if(flags & F_WHITE_ON_MOVE) {
-#if 0
-    if (appData.debugMode) {
-        fprintf(debugFP, "Disambiguate B:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
-                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
-                          closure->promoCharIn,closure->promoCharIn);
-    }
-#endif
                 if( (int) piece < (int) WhiteWazir &&
-                     (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) {
+                     (closure->rf >= BOARD_HEIGHT-(BOARD_HEIGHT/3) || closure->rt >= BOARD_HEIGHT-(BOARD_HEIGHT/3)) ) {
                     if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||
                          piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */
-                             closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight;
+                             closure->kind = c == '=' ? IllegalMove : WhitePromotion;
                     else /* promotion optional, default is promote */
-                             closure->kind = c == '=' ? NormalMove  : WhitePromotionQueen;
-                   
-                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?
-                                            NormalMove : IllegalMove;
+                             closure->kind = c == '=' ? WhiteNonPromotion  : WhitePromotion;
+                } else closure->kind = (c == NULLCHAR || c == '=') ? NormalMove : IllegalMove;
             } else {
-                if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) {
+                if( (int) piece < (int) BlackWazir && (closure->rf < BOARD_HEIGHT/3 || closure->rt < BOARD_HEIGHT/3) ) {
                     if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||
                          piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */
-                             closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight;
+                             closure->kind = c == '=' ? IllegalMove : BlackPromotion;
                     else /* promotion optional, default is promote */
-                             closure->kind = c == '=' ? NormalMove  : BlackPromotionQueen;
-
-                } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ?
-                                            NormalMove : IllegalMove;
+                             closure->kind = c == '=' ? BlackNonPromotion  : BlackPromotion;
+                } else closure->kind = (c == NULLCHAR || c == '=') ? NormalMove : IllegalMove;
             }
         }
+        c = (closure->kind == WhitePromotion || closure->kind == BlackPromotion) ? '+' : NULLCHAR;
     } else
-    if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {
-       if (closure->kind == WhitePromotionQueen
-           || closure->kind == BlackPromotionQueen) {
-           closure->kind = 
-             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,
-                                 closure->promoCharIn);
-       } else {
-           closure->kind = IllegalMove;
-       }
-    }
-#if 0
-    if (appData.debugMode) {
-        fprintf(debugFP, "Disambiguate C:   %d(%d,%d)-(%d,%d) = %d (%c)\n",
-                          closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
-                          closure->promoCharIn,closure->promoCharIn);
-    }
-#endif
-    /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */
-    if(closure->promoCharIn != '=')
-        closure->promoChar = ToLower(closure->promoCharIn);
-    else closure->promoChar = '=';
-    if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;
+    if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) {
+        if(c == NULLCHAR) c = 'q'; // even in Shatranj, Courier, Makruk, as Apply move corrects this to Ferz (how messy!)
+    } else if (c != NULLCHAR) closure->kind = IllegalMove;
+
+    closure->promoChar = ToLower(c); // this can be NULLCHAR! Note we keep original promoChar even if illegal.
+    if(c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare) closure->kind = ImpossibleMove; // but we cannot handle non-existing piece types! 
     if (closure->count > 1) {
        closure->kind = AmbiguousMove;
     }
@@ -1294,9 +1270,6 @@ void Disambiguate(board, flags, epfile, closure)
        */
        closure->kind = IllegalMove;
     }
-    if(closure->kind == IllegalMove)
-    /* [HGM] might be a variant we don't understand, pass on promotion info */
-        closure->promoChar = ToLower(closure->promoCharIn);
     if (appData.debugMode) {
         fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n",
         closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar,
@@ -1354,10 +1327,9 @@ void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
 /* Convert coordinates to normal algebraic notation.
    promoChar must be NULLCHAR or 'x' if not a promotion.
 */
-ChessMove CoordsToAlgebraic(board, flags, epfile,
-                           rf, ff, rt, ft, promoChar, out)
+ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out)
      Board board;
-     int flags, epfile;
+     int flags;
      int rf, ff, rt, ft;
      int promoChar;
      char out[MOVE_LEN];
@@ -1388,12 +1360,11 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
     switch (piece) {
       case WhitePawn:
       case BlackPawn:
-        kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);
+        kind = LegalityTest(board, flags, rf, ff, rt, ft, promoChar);
        if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
            /* Keep short notation if move is illegal only because it
                leaves the player in check, but still return IllegalMove */
-            kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,
-                              rf, ff, rt, ft, promoChar);
+            kind = LegalityTest(board, flags|F_IGNORE_CHECK, rf, ff, rt, ft, promoChar);
            if (kind == IllegalMove) break;
            kind = IllegalMove;
        }
@@ -1437,14 +1408,14 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
        if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||
           (piece == BlackKing && board[rt][ft] == BlackRook)) {
          if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");
-            return LegalityTest(board, flags, epfile, initialRights,
-                               rf, ff, rt, ft, promoChar);
+            return LegalityTest(board, flags, rf, ff, rt, ft, promoChar);
        }
        /* End of code added by Tord */
        /* Test for castling or ICS wild castling */
        /* Use style "O-O" (oh-oh) for PGN compatibility */
        else if (rf == rt &&
            rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&
+            (ft - ff > 1 || ff - ft > 1) &&  // No castling if legal King move (on narrow boards!)
             ((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)
@@ -1460,8 +1431,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
               this situation.  So I am not going to worry about it;
               I'll just generate an ambiguous O-O in this case.
            */
-            return LegalityTest(board, flags, epfile, initialRights,
-                               rf, ff, rt, ft, promoChar);
+            return LegalityTest(board, flags, rf, ff, rt, ft, promoChar);
        }
 
        /* else fall through */
@@ -1474,15 +1444,13 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
        cl.piece = piece;
        cl.kind = IllegalMove;
        cl.rank = cl.file = cl.either = 0;
-        GenLegal(board, flags, epfile, initialRights,
-                CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+        GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
 
        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, epfile, initialRights,
-                    CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+            GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
            if (cl.kind == IllegalMove) break;
            cl.kind = IllegalMove;
        }
@@ -1521,24 +1489,24 @@ ChessMove CoordsToAlgebraic(board, flags, epfile,
             /* [HGM] in Shogi non-pawns can promote */
             if(flags & F_WHITE_ON_MOVE) {
                 if( (int) cl.piece < (int) WhiteWazir &&
-                     (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) {
+                     (rf >= BOARD_HEIGHT-(BOARD_HEIGHT/3) || rt >= BOARD_HEIGHT-(BOARD_HEIGHT/3)) ) {
                     if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
                          piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
-                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight;
-                    else cl.kind =  WhitePromotionQueen; /* promotion optional */
+                             cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion;
+                    else cl.kind =  WhitePromotion; /* promotion optional */
                    
                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
                                             NormalMove : IllegalMove;
             } else {
-                if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) {
+                if( (int) cl.piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) {
                     if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
                          piece == BlackKnight && rt < 2 ) /* promotion obligatory */
-                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight;
-                    else cl.kind =  BlackPromotionQueen; /* promotion optional */
+                             cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion;
+                    else cl.kind =  BlackPromotion; /* promotion optional */
                 } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
                                             NormalMove : IllegalMove;
             }
-            if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
+            if(cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
                 /* for optional promotions append '+' or '=' */
                 if(promoChar == '=') {
                     *outp++ = '=';
@@ -1709,7 +1677,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), EP_NONE, initialRights, AttacksCallback, &cl);
+       GenLegal(boards[i+1], PosFlags(i), AttacksCallback, &cl);
        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, 
@@ -1721,7 +1689,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), EP_NONE, initialRights, ExistingAttacksCallback, &cl);
+       GenLegal(boards[i],   PosFlags(i), ExistingAttacksCallback, &cl);
        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, 
@@ -1740,7 +1708,7 @@ int PerpetualChase(int first, int last)
                continue; // C or H attack on R is always chase; leave on chaseStack
 
            if(attacker == victim) {
-                if(LegalityTest(boards[i+1], PosFlags(i+1), EP_NONE, initialRights, chaseStack[j].rt, 
+                if(LegalityTest(boards[i+1], PosFlags(i+1), chaseStack[j].rt, 
                    chaseStack[j].ft, chaseStack[j].rf, chaseStack[j].ff, NULLCHAR) == NormalMove) {
                        // we can capture back with equal piece, so this is no chase but a sacrifice
                         chaseStack[j] = chaseStack[--chaseStackPointer]; // delete the capture from the chaseStack
@@ -1761,7 +1729,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), EP_NONE, initialRights, ProtectedCallback, &cl); // try all moves
+            GenLegal(boards[i+1], PosFlags(i+1), ProtectedCallback, &cl); // 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;