changes from H.G. Muller; version 4.3.2
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index accbfed..57e350e 100644 (file)
--- a/moves.c
+++ b/moves.c
-/*
- * 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-95 Free Software Foundation, Inc.
- *
- * The following terms apply to Digital Equipment Corporation's copyright
- * interest in XBoard:
- * ------------------------------------------------------------------------
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of Digital not be
- * used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- *
- * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- * ------------------------------------------------------------------------
- *
- * The following terms apply to the enhanced version of XBoard distributed
- * by the Free Software Foundation:
- * ------------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * ------------------------------------------------------------------------
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#if HAVE_STRING_H
-# include <string.h>
-#else /* not HAVE_STRING_H */
-# include <strings.h>
-#endif /* not HAVE_STRING_H */
-#include "common.h"
-#include "backend.h" 
-#include "moves.h"
-#include "parser.h"
-
-int WhitePiece P((ChessSquare));
-int BlackPiece P((ChessSquare));
-int SameColor P((ChessSquare, ChessSquare));
-
-
-int WhitePiece(piece)
-     ChessSquare piece;
-{
-    return (int) piece >= (int) WhitePawn && (int) piece <= (int) WhiteKing;
-}
-
-int BlackPiece(piece)
-     ChessSquare piece;
-{
-    return (int) piece >= (int) BlackPawn && (int) piece <= (int) BlackKing;
-}
-
-int SameColor(piece1, piece2)
-     ChessSquare piece1, piece2;
-{
-    return ((int) piece1 >= (int) WhitePawn &&
-           (int) piece1 <= (int) WhiteKing &&
-           (int) piece2 >= (int) WhitePawn &&
-           (int) piece2 <= (int) WhiteKing)
-      ||   ((int) piece1 >= (int) BlackPawn &&
-           (int) piece1 <= (int) BlackKing &&
-           (int) piece2 >= (int) BlackPawn &&
-           (int) piece2 <= (int) BlackKing);
-}
-
-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;
-    }
-}
-
-ChessMove PromoCharToMoveType(whiteOnMove, promoChar)
-     int whiteOnMove;
-     int promoChar;
-{
-    if (whiteOnMove) {
-       switch (promoChar) {
-         case 'n':
-         case 'N':
-           return WhitePromotionKnight;
-         case 'b':
-         case 'B':
-           return WhitePromotionBishop;
-         case 'r':
-         case 'R':
-           return WhitePromotionRook;
-         case 'q':
-         case 'Q':
-           return WhitePromotionQueen;
-         case 'k':
-         case 'K':
-           return WhitePromotionKing;
-         case NULLCHAR:
-         default:
-           return NormalMove;
-       }
-    } else {
-       switch (promoChar) {
-         case 'n':
-         case 'N':
-           return BlackPromotionKnight;
-         case 'b':
-         case 'B':
-           return BlackPromotionBishop;
-         case 'r':
-         case 'R':
-           return BlackPromotionRook;
-         case 'q':
-         case 'Q':
-           return BlackPromotionQueen;
-         case 'k':
-         case 'K':
-           return BlackPromotionKing;
-         case NULLCHAR:
-         default:
-           return NormalMove;
-       }
-    }
-}
-
-char pieceToChar[] = {
-    'P', 'N', 'B', 'R', 'Q', 'K',
-    'p', 'n', 'b', 'r', 'q', 'k', 'x'
-  };
-
-char PieceToChar(p)
-     ChessSquare p;
-{
-    return pieceToChar[(int) p];
-}
-
-ChessSquare CharToPiece(c)
-     int c;
-{
-    switch (c) {
-      default:
-      case 'x':        return EmptySquare;
-      case 'P':        return WhitePawn;
-      case 'R':        return WhiteRook;
-      case 'N':        return WhiteKnight;
-      case 'B':        return WhiteBishop;
-      case 'Q':        return WhiteQueen;
-      case 'K':        return WhiteKing;
-      case 'p':        return BlackPawn;
-      case 'r':        return BlackRook;
-      case 'n':        return BlackKnight;
-      case 'b':        return BlackBishop;
-      case 'q':        return BlackQueen;
-      case 'k':        return BlackKing;
-    }
-}
-
-void CopyBoard(to, from)
-     Board to, from;
-{
-    int i, j;
-    
-    for (i = 0; i < BOARD_SIZE; i++)
-      for (j = 0; j < BOARD_SIZE; j++)
-       to[i][j] = from[i][j];
-}
-
-int CompareBoards(board1, board2)
-     Board board1, board2;
-{
-    int i, j;
-    
-    for (i = 0; i < BOARD_SIZE; i++)
-      for (j = 0; j < BOARD_SIZE; j++) {
-         if (board1[i][j] != board2[i][j])
-           return FALSE;
-    }
-    return TRUE;
-}
-
-
-/* Call callback once for each pseudo-legal move in the given
-   position, except castling moves. A move is pseudo-legal if it is
-   legal, or if it would be legal except that it leaves the king in
-   check.  In the arguments, epfile is EP_NONE if the previous move
-   was not a double pawn push, or the file 0..7 if it was, or
-   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)
-     Board board;
-     int flags;
-     int epfile;
-     MoveCallback callback;
-     VOIDSTAR closure;
-{
-    int rf, ff;
-    int i, j, d, s, fs, rs, rt, ft;
-
-    for (rf = 0; rf <= 7; rf++) 
-      for (ff = 0; ff <= 7; ff++) {
-         if (flags & F_WHITE_ON_MOVE) {
-             if (!WhitePiece(board[rf][ff])) continue;
-         } else {
-             if (!BlackPiece(board[rf][ff])) continue;
-         }
-         switch (board[rf][ff]) {
-           case EmptySquare:
-           default:
-             /* can't happen */
-             break;
-
-           case WhitePawn:
-             if (rf < 7 && board[rf + 1][ff] == EmptySquare) {
-                 callback(board, flags,
-                          rf == 6 ? WhitePromotionQueen : NormalMove,
-                          rf, ff, rf + 1, ff, closure);
-             }
-             if (rf == 1 && board[2][ff] == EmptySquare &&
-                 board[3][ff] == EmptySquare) {
-                 callback(board, flags, NormalMove,
-                          rf, ff, 3, ff, closure);
-             }
-             for (s = -1; s <= 1; s += 2) {
-                 if (rf < 7 && ff + s >= 0 && ff + s <= 7 &&
-                     ((flags & F_KRIEGSPIEL_CAPTURE) ||
-                      BlackPiece(board[rf + 1][ff + s]))) {
-                     callback(board, flags, 
-                              rf == 6 ? WhitePromotionQueen : NormalMove,
-                              rf, ff, rf + 1, ff + s, closure);
-                 }
-                 if (rf == 4) {
-                     if (ff + s >= 0 && ff + s <= 7 &&
-                         (epfile == ff + s || epfile == EP_UNKNOWN) &&
-                         board[4][ff + s] == BlackPawn &&
-                         board[5][ff + s] == EmptySquare) {
-                         callback(board, flags, WhiteCapturesEnPassant,
-                                  rf, ff, 5, ff + s, closure);
-                     }
-                 }
-             }             
-             break;
-
-           case BlackPawn:
-             if (rf > 0 && board[rf - 1][ff] == EmptySquare) {
-                 callback(board, flags, 
-                          rf == 1 ? BlackPromotionQueen : NormalMove,
-                          rf, ff, rf - 1, ff, closure);
-             }
-             if (rf == 6 && board[5][ff] == EmptySquare &&
-                 board[4][ff] == EmptySquare) {
-                 callback(board, flags, NormalMove,
-                          rf, ff, 4, ff, closure);
-             }
-             for (s = -1; s <= 1; s += 2) {
-                 if (rf > 0 && ff + s >= 0 && ff + s <= 7 &&
-                     ((flags & F_KRIEGSPIEL_CAPTURE) ||
-                      WhitePiece(board[rf - 1][ff + s]))) {
-                     callback(board, flags, 
-                              rf == 1 ? BlackPromotionQueen : NormalMove,
-                              rf, ff, rf - 1, ff + s, closure);
-                 }
-                 if (rf == 3) {
-                     if (ff + s >= 0 && ff + s <= 7 &&
-                         (epfile == ff + s || epfile == EP_UNKNOWN) &&
-                         board[3][ff + s] == WhitePawn &&
-                         board[2][ff + s] == EmptySquare) {
-                         callback(board, flags, BlackCapturesEnPassant,
-                                  rf, ff, 2, ff + s, closure);
-                     }
-                 }
-             }             
-             break;
-
-           case WhiteKnight:
-           case BlackKnight:
-             for (i = -1; i <= 1; i += 2)
-               for (j = -1; j <= 1; j += 2)
-                 for (s = 1; s <= 2; s++) {
-                     rt = rf + i*s;
-                     ft = ff + j*(3-s);
-                     if (rt < 0 || rt > 7 || ft < 0 || ft > 7) continue;
-                     if (SameColor(board[rf][ff], board[rt][ft])) continue;
-                     callback(board, flags, NormalMove,
-                              rf, ff, rt, ft, closure);
-                 }
-             break;
-
-           case WhiteBishop:
-           case BlackBishop:
-             for (rs = -1; rs <= 1; rs += 2) 
-               for (fs = -1; fs <= 1; fs += 2)
-                 for (i = 1;; i++) {
-                     rt = rf + (i * rs);
-                     ft = ff + (i * fs);
-                     if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break;
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;
-                     callback(board, flags, NormalMove,
-                              rf, ff, rt, ft, closure);
-                     if (board[rt][ft] != EmptySquare) break;
-                 }
-             break;
-
-           case WhiteRook:
-           case BlackRook:
-             for (d = 0; d <= 1; d++)
-               for (s = -1; s <= 1; s += 2)
-                 for (i = 1;; i++) {
-                     rt = rf + (i * s) * d;
-                     ft = ff + (i * s) * (1 - d);
-                     if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break;
-                     if (SameColor(board[rf][ff], board[rt][ft])) break;
-                     callback(board, flags, NormalMove,
-                              rf, ff, rt, ft, closure);
-                     if (board[rt][ft] != EmptySquare) break;
-                 }
-             break;
-
-           case WhiteQueen:
-           case BlackQueen:
-             for (rs = -1; rs <= 1; rs++) 
-               for (fs = -1; fs <= 1; fs++) {
-                   if (rs == 0 && fs == 0) continue;
-                   for (i = 1;; i++) {
-                       rt = rf + (i * rs);
-                       ft = ff + (i * fs);
-                       if (rt < 0 || rt > 7 || ft < 0 || ft > 7) break;
-                       if (SameColor(board[rf][ff], board[rt][ft])) break;
-                       callback(board, flags, NormalMove,
-                                rf, ff, rt, ft, closure);
-                       if (board[rt][ft] != EmptySquare) break;
-                   }
-               }
-             break;
-
-           case WhiteKing:
-           case BlackKing:
-             for (i = -1; i <= 1; i++)
-               for (j = -1; j <= 1; j++) {
-                   if (i == 0 && j == 0) continue;
-                   rt = rf + i;
-                   ft = ff + j;
-                   if (rt < 0 || rt > 7 || ft < 0 || ft > 7) continue;
-                   if (SameColor(board[rf][ff], board[rt][ft])) continue;
-                   callback(board, flags, NormalMove,
-                            rf, ff, rt, ft, closure);
-               }
-             break;
-         }
-      }
-}
-
-
-typedef struct {
-    MoveCallback cb;
-    VOIDSTAR cl;
-} GenLegalClosure;
-
-extern void GenLegalCallback P((Board board, int flags, ChessMove kind,
-                               int rf, int ff, int rt, int ft,
-                               VOIDSTAR closure));
-
-void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
-{
-    register GenLegalClosure *cl = (GenLegalClosure *) closure;
-
-    if (!(flags & F_IGNORE_CHECK) &&
-       CheckTest(board, flags, rf, ff, rt, ft,
-                 kind == WhiteCapturesEnPassant ||
-                 kind == BlackCapturesEnPassant)) return;
-    if (flags & F_ATOMIC_CAPTURE) {
-      if (board[rt][ft] != EmptySquare ||
-         kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
-       int r, f;
-       ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;
-       if (board[rf][ff] == king) return;
-       for (r = rt-1; r <= rt+1; r++) {
-         for (f = ft-1; f <= ft+1; f++) {
-           if (r >= 0 && r <= 7 && f >= 0 && f <= 7 &&
-               board[r][f] == king) return;
-         }
-       }
-      }
-    }
-    cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);
-}
-
-
-typedef struct {
-    int rf, ff, rt, ft;
-    ChessMove kind;
-} LegalityTestClosure;
-
-
-/* Like GenPseudoLegal, but (1) include castling moves, (2) unless
-   F_IGNORE_CHECK is set in the flags, omit moves that would leave the
-   king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit
-   moves that would destroy your own king.  The CASTLE_OK flags are
-   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.  */
-int GenLegal(board, flags, epfile, callback, closure)
-     Board board;
-     int flags;
-     int epfile;
-     MoveCallback callback;
-     VOIDSTAR closure;
-{
-    GenLegalClosure cl;
-    int ff, ft;
-    int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;
-
-    cl.cb = callback;
-    cl.cl = closure;
-    GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);
-
-    if (!ignoreCheck &&
-       CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;
-
-    /* Generate castling moves */
-    for (ff = 4; ff >= 3; ff-- /*ics wild 1*/) {
-       if ((flags & F_WHITE_ON_MOVE) &&
-           (flags & F_WHITE_KCASTLE_OK) &&
-           board[0][ff] == WhiteKing &&
-           board[0][ff + 1] == EmptySquare &&
-           board[0][ff + 2] == EmptySquare &&
-           board[0][6] == EmptySquare &&
-           board[0][7] == WhiteRook &&
-           (ignoreCheck ||
-            (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&
-             !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {
-
-           callback(board, flags,
-                    ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,
-                    0, ff, 0, ff + 2, closure);
-       }
-       if ((flags & F_WHITE_ON_MOVE) &&
-           (flags & F_WHITE_QCASTLE_OK) &&
-           board[0][ff] == WhiteKing &&
-           board[0][ff - 1] == EmptySquare &&
-           board[0][ff - 2] == EmptySquare &&
-           board[0][1] == EmptySquare &&
-           board[0][0] == WhiteRook &&
-           (ignoreCheck ||
-            (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&
-             !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {
-
-           callback(board, flags,
-                    ff==4 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,
-                    0, ff, 0, ff - 2, closure);
-       }
-       if (!(flags & F_WHITE_ON_MOVE) &&
-           (flags & F_BLACK_KCASTLE_OK) &&
-           board[7][ff] == BlackKing &&
-           board[7][ff + 1] == EmptySquare &&
-           board[7][ff + 2] == EmptySquare &&
-           board[7][6] == EmptySquare &&
-           board[7][7] == BlackRook &&
-           (ignoreCheck ||
-            (!CheckTest(board, flags, 7, ff, 7, ff + 1, FALSE) &&
-             !CheckTest(board, flags, 7, ff, 7, ff + 2, FALSE)))) {
-
-           callback(board, flags,
-                    ff==4 ? BlackKingSideCastle : BlackKingSideCastleWild,
-                    7, ff, 7, ff + 2, closure);
-       }
-       if (!(flags & F_WHITE_ON_MOVE) &&
-           (flags & F_BLACK_QCASTLE_OK) &&
-           board[7][ff] == BlackKing &&
-           board[7][ff - 1] == EmptySquare &&
-           board[7][ff - 2] == EmptySquare &&
-           board[7][1] == EmptySquare &&
-           board[7][0] == BlackRook &&
-           (ignoreCheck ||
-            (!CheckTest(board, flags, 7, ff, 7, ff - 1, FALSE) &&
-             !CheckTest(board, flags, 7, ff, 7, ff - 1, FALSE)))) {
-
-           callback(board, flags,
-                    ff==4 ? BlackQueenSideCastle : BlackQueenSideCastleWild,
-                    7, ff, 7, ff - 2, closure);
-       }
-    }
-
-    /* PUSH Fabien */
-
-    /* generate all potential FRC castling moves (KxR), ignoring flags */
-
-    if ((flags & F_WHITE_ON_MOVE) != 0) {
-
-       for (ff = 1; ff < 7; ff++) {
-          if (board[0][ff] == WhiteKing) {
-             for (ft = 0; ft < 8; ft++) {
-                if (board[0][ft] == WhiteRook) {
-                   callback(board, flags,
-                            (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR,
-                            0, ff, 0, ft, closure);
-                }
-             }
-          }
-       }
-
-    } else {
-
-       for (ff = 1; ff < 7; ff++) {
-          if (board[7][ff] == BlackKing) {
-             for (ft = 0; ft < 8; ft++) {
-                if (board[7][ft] == BlackRook) {
-                   callback(board, flags,
-                            (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR,
-                            7, ff, 7, ft, closure);
-                }
-             }
-          }
-       }
-    }
-
-    /* POP Fabien */
-
-    return FALSE;
-}
-
-
-typedef struct {
-    int rking, fking;
-    int check;
-} CheckTestClosure;
-
-
-extern void CheckTestCallback P((Board board, int flags, ChessMove kind,
-                                int rf, int ff, int rt, int ft,
-                                VOIDSTAR closure));
-
-
-void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
-{
-    register CheckTestClosure *cl = (CheckTestClosure *) closure;
-
-    if (rt == cl->rking && ft == cl->fking) cl->check++;
-}
-
-
-/* If the player on move were to move from (rf, ff) to (rt, ft), would
-   he leave himself in check?  Or if rf == -1, is the player on move
-   in check now?  enPassant must be TRUE if the indicated move is an
-   e.p. capture.  The possibility of castling out of a check along the
-   back rank is not accounted for (i.e., we still return nonzero), as
-   this is illegal anyway.  Return value is the number of times the
-   king is in check. */ 
-int CheckTest(board, flags, rf, ff, rt, ft, enPassant)
-     Board board;
-     int flags;
-     int rf, ff, rt, ft, enPassant;
-{
-    CheckTestClosure cl;
-    ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
-    ChessSquare captured = EmptySquare;
-    /*  Suppress warnings on uninitialized variables    */
-
-    if (rf >= 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;
-    }
-
-    /* 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 = 0; cl.fking <= 7; cl.fking++)
-       for (cl.rking = 0; cl.rking <= 7; cl.rking++) {
-         if (board[cl.rking][cl.fking] == king) {
-             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,
-                            CheckTestCallback, (VOIDSTAR) &cl);
-             goto undo_move;  /* 2-level break */
-         }
-      }
-
-  undo_move:
-
-    if (rf >= 0) {
-       board[rf][ff] = board[rt][ft];
-       if (enPassant) {
-           board[rf][ft] = captured;
-           board[rt][ft] = EmptySquare;
-       } else {
-           board[rt][ft] = captured;
-       }
-    }
-
-    return cl.check;
-}
-
-
-extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,
-                                   int rf, int ff, int rt, int ft,
-                                   VOIDSTAR closure));
-
-void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
-{
-    register LegalityTestClosure *cl = (LegalityTestClosure *) closure;
-
-    if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)
-      cl->kind = kind;
-}
-
-ChessMove LegalityTest(board, flags, epfile, rf, ff, rt, ft, promoChar)
-     Board board;
-     int flags, epfile;
-     int rf, ff, rt, ft, promoChar;
-{
-    LegalityTestClosure cl;
-    
-    cl.rf = rf;
-    cl.ff = ff;
-    cl.rt = rt;
-    cl.ft = ft;
-    cl.kind = IllegalMove;
-    GenLegal(board, flags, epfile, LegalityTestCallback, (VOIDSTAR) &cl);
-    if (promoChar != NULLCHAR && promoChar != 'x') {
-       if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {
-           cl.kind = 
-             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);
-       } else {
-           cl.kind = IllegalMove;
-       }
-    }
-    return cl.kind;
-}
-
-typedef struct {
-    int count;
-} MateTestClosure;
-
-extern void MateTestCallback P((Board board, int flags, ChessMove kind,
-                               int rf, int ff, int rt, int ft,
-                               VOIDSTAR closure));
-
-void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
-{
-    register MateTestClosure *cl = (MateTestClosure *) closure;
-
-    cl->count++;
-}
-
-/* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */
-int MateTest(board, flags, epfile)
-     Board board;
-     int flags, epfile;
-{
-    MateTestClosure cl;
-    int inCheck;
-
-    cl.count = 0;
-    inCheck = GenLegal(board, flags, epfile, MateTestCallback, (VOIDSTAR) &cl);
-    if (cl.count > 0) {
-       return inCheck ? MT_CHECK : MT_NONE;
-    } else {
-       return inCheck ? MT_CHECKMATE : MT_STALEMATE;
-    }
-}
-
-     
-extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,
-                                   int rf, int ff, int rt, int ft,
-                                   VOIDSTAR closure));
-
-void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
-{
-    register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
-
-    if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&
-       (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->count++;
-       cl->piece = board[rf][ff];
-       cl->rf = rf;
-       cl->ff = ff;
-       cl->rt = rt;
-       cl->ft = ft;
-       cl->kind = kind;
-    }
-}
-
-void Disambiguate(board, flags, epfile, closure)
-     Board board;
-     int flags, epfile;
-     DisambiguateClosure *closure;
-{
-    int illegal = 0;
-    closure->count = 0;
-    closure->rf = closure->ff = closure->rt = closure->ft = 0;
-    closure->kind = ImpossibleMove;
-    GenLegal(board, flags, epfile, 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, DisambiguateCallback,
-                (VOIDSTAR) closure);   
-       if (closure->count == 0) {
-           /* No, it's not even that */
-           return;
-       }
-    }
-    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;
-       }
-    }
-    closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));
-    if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;
-    if (closure->count > 1) {
-       closure->kind = AmbiguousMove;
-    }
-    if (illegal) {
-       /* Note: If more than one illegal move matches, but no legal
-          moves, we return IllegalMove, not AmbiguousMove.  Caller
-          can look at closure->count to detect this.
-       */
-       closure->kind = IllegalMove;
-    }
-}
-
-
-typedef struct {
-    /* Input */
-    ChessSquare piece;
-    int rf, ff, rt, ft;
-    /* Output */
-    ChessMove kind;
-    int rank;
-    int file;
-    int either;
-} CoordsToAlgebraicClosure;
-
-extern void CoordsToAlgebraicCallback P((Board board, int flags,
-                                        ChessMove kind, int rf, int ff,
-                                        int rt, int ft, VOIDSTAR closure));
-
-void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)
-     Board board;
-     int flags;
-     ChessMove kind;
-     int rf, ff, rt, ft;
-     VOIDSTAR closure;
-{
-    register CoordsToAlgebraicClosure *cl =
-      (CoordsToAlgebraicClosure *) closure;
-
-    if (rt == cl->rt && ft == cl->ft &&
-       board[rf][ff] == cl->piece) {
-       if (rf == cl->rf) {
-           if (ff == cl->ff) {
-               cl->kind = kind; /* this is the move we want */
-           } else {
-               cl->file++; /* need file to rule out this move */
-           }
-       } else {
-           if (ff == cl->ff) {
-               cl->rank++; /* need rank to rule out this move */
-           } else {
-               cl->either++; /* rank or file will rule out this move */
-           }
-       }           
-    }
-}
-
-/* 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)
-     Board board;
-     int flags, epfile;
-     int rf, ff, rt, ft;
-     int promoChar;
-     char out[MOVE_LEN];
-{
-    ChessSquare piece;
-    ChessMove kind;
-    char *outp = out;
-    CoordsToAlgebraicClosure cl;
-    
-    if (rf == DROP_RANK) {
-       /* Bughouse piece drop */
-       *outp++ = ToUpper(PieceToChar((ChessSquare) ff));
-       *outp++ = '@';
-       *outp++ = ft + 'a';
-       *outp++ = rt + '1';
-       *outp = NULLCHAR;
-       return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;
-    }
-
-    if (promoChar == 'x') promoChar = NULLCHAR;
-    piece = board[rf][ff];
-    switch (piece) {
-      case WhitePawn:
-      case BlackPawn:
-       kind = LegalityTest(board, flags, epfile, 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,
-                              rf, ff, rt, ft, promoChar);
-           if (kind == IllegalMove) break;
-           kind = IllegalMove;
-       }
-       /* Pawn move */
-       *outp++ = ff + 'a';
-       if (ff == ft) {
-           /* Non-capture; use style "e5" */
-           *outp++ = rt + '1';
-       } else {
-           /* Capture; use style "exd5" */
-           *outp++ = 'x';
-           *outp++ = ft + 'a';
-           *outp++ = rt + '1';
-       }
-       /* Use promotion suffix style "=Q" */
-       if (promoChar != NULLCHAR && promoChar != 'x') {
-           *outp++ = '=';
-           *outp++ = ToUpper(promoChar);
-       }
-       *outp = NULLCHAR;
-       return kind;
-
-       
-      case WhiteKing:
-      case BlackKing:
-        /* Fabien moved code: FRC castling first (if KxR), wild castling second */
-       /* Code added by Tord:  FRC castling. */
-       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,
-                               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 : 7) &&
-           ((ff == 4 && (ft == 2 || ft == 6)) ||
-            (ff == 3 && (ft == 1 || ft == 5)))) {
-           switch (ft) {
-             case 1:
-             case 6:
-               strcpy(out, "O-O");
-               break;
-             case 2:
-             case 5:
-               strcpy(out, "O-O-O");
-               break;
-           }
-           /* This notation is always unambiguous, unless there are
-              kings on both the d and e files, with "wild castling"
-              possible for the king on the d file and normal castling
-              possible for the other.  ICS rules for wild 9
-              effectively make castling illegal for either king in
-              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,
-                               rf, ff, rt, ft, promoChar);
-       }
-
-       /* else fall through */
-       
-      default:
-       /* Piece move */
-       cl.rf = rf;
-       cl.ff = ff;
-       cl.rt = rt;
-       cl.ft = ft;
-       cl.piece = piece;
-       cl.kind = IllegalMove;
-       cl.rank = cl.file = cl.either = 0;
-       GenLegal(board, flags, epfile,
-                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,
-                    CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
-           if (cl.kind == IllegalMove) break;
-           cl.kind = IllegalMove;
-       }
-
-       /* Style is "Nf3" or "Nxf7" if this is unambiguous,
-          else "Ngf3" or "Ngxf7",
-          else "N1f3" or "N5xf7",
-          else "Ng1f3" or "Ng5xf7".
-       */
-       *outp++ = ToUpper(PieceToChar(piece));
-       
-       if (cl.file || (cl.either && !cl.rank)) {
-           *outp++ = ff + 'a';
-       }
-       if (cl.rank) {
-           *outp++ = rf + '1';
-       }
-
-       if(board[rt][ft] != EmptySquare)
-         *outp++ = 'x';
-
-       *outp++ = ft + 'a';
-       *outp++ = rt + '1';
-       *outp = NULLCHAR;
-       return cl.kind;
-       
-      case EmptySquare:
-       /* Moving a nonexistent piece */
-       break;
-    }
-    
-    /* Not a legal move, even ignoring check.
-       If there was a piece on the from square, 
-       use style "Ng1g3" or "Ng1xe8";
-       if there was a pawn or nothing (!),
-       use style "g1g3" or "g1xe8".  Use "x"
-       if a piece was on the to square, even
-       a piece of the same color.
-    */
-    outp = out;
-    if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {
-       *outp++ = ToUpper(PieceToChar(piece));
-    }
-    *outp++ = ff + 'a';
-    *outp++ = rf + '1';
-    if (board[rt][ft] != EmptySquare) *outp++ = 'x';
-    *outp++ = ft + 'a';
-    *outp++ = rt + '1';
-    /* Use promotion suffix style "=Q" */
-    if (promoChar != NULLCHAR && promoChar != 'x') {
-       *outp++ = '=';
-       *outp++ = ToUpper(promoChar);
-    }
-    *outp = NULLCHAR;
-
-    return IllegalMove;
-}
+/*\r
+ * moves.c - Move generation and checking\r
+ * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $\r
+ *\r
+ * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.\r
+ * Enhancements Copyright 1992-95 Free Software Foundation, Inc.\r
+ *\r
+ * The following terms apply to Digital Equipment Corporation's copyright\r
+ * interest in XBoard:\r
+ * ------------------------------------------------------------------------\r
+ * All Rights Reserved\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation for any purpose and without fee is hereby granted,\r
+ * provided that the above copyright notice appear in all copies and that\r
+ * both that copyright notice and this permission notice appear in\r
+ * supporting documentation, and that the name of Digital not be\r
+ * used in advertising or publicity pertaining to distribution of the\r
+ * software without specific, written prior permission.\r
+ *\r
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
+ * SOFTWARE.\r
+ * ------------------------------------------------------------------------\r
+ *\r
+ * The following terms apply to the enhanced version of XBoard distributed\r
+ * by the Free Software Foundation:\r
+ * ------------------------------------------------------------------------\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+ * ------------------------------------------------------------------------\r
+ */\r
+\r
+#include "config.h"\r
+\r
+#include <stdio.h>\r
+#if HAVE_STRING_H\r
+# include <string.h>\r
+#else /* not HAVE_STRING_H */\r
+# include <strings.h>\r
+#endif /* not HAVE_STRING_H */\r
+#include "common.h"\r
+#include "backend.h" \r
+#include "moves.h"\r
+#include "parser.h"\r
+\r
+int WhitePiece P((ChessSquare));\r
+int BlackPiece P((ChessSquare));\r
+int SameColor P((ChessSquare, ChessSquare));\r
+\r
+extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */\r
+\r
+\r
+int WhitePiece(piece)\r
+     ChessSquare piece;\r
+{\r
+    return (int) piece >= (int) WhitePawn && (int) piece < (int) BlackPawn;\r
+}\r
+\r
+int BlackPiece(piece)\r
+     ChessSquare piece;\r
+{\r
+    return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare;\r
+}\r
+\r
+int SameColor(piece1, piece2)\r
+     ChessSquare piece1, piece2;\r
+{\r
+    return ((int) piece1 >= (int) WhitePawn &&   /* [HGM] can be > King ! */\r
+            (int) piece1 <  (int) BlackPawn &&\r
+           (int) piece2 >= (int) WhitePawn &&\r
+            (int) piece2 <  (int) BlackPawn)\r
+      ||   ((int) piece1 >= (int) BlackPawn &&\r
+            (int) piece1 <  (int) EmptySquare &&\r
+           (int) piece2 >= (int) BlackPawn &&\r
+            (int) piece2 <  (int) EmptySquare);\r
+}\r
+\r
+ChessSquare PromoPiece(moveType)\r
+     ChessMove moveType;\r
+{\r
+    switch (moveType) {\r
+      default:\r
+       return EmptySquare;\r
+      case WhitePromotionQueen:\r
+       return WhiteQueen;\r
+      case BlackPromotionQueen:\r
+       return BlackQueen;\r
+      case WhitePromotionRook:\r
+       return WhiteRook;\r
+      case BlackPromotionRook:\r
+       return BlackRook;\r
+      case WhitePromotionBishop:\r
+       return WhiteBishop;\r
+      case BlackPromotionBishop:\r
+       return BlackBishop;\r
+      case WhitePromotionKnight:\r
+       return WhiteKnight;\r
+      case BlackPromotionKnight:\r
+       return BlackKnight;\r
+      case WhitePromotionKing:\r
+       return WhiteKing;\r
+      case BlackPromotionKing:\r
+       return BlackKing;\r
+#ifdef FAIRY\r
+      case WhitePromotionChancellor:\r
+        return WhiteFairyRook;\r
+      case BlackPromotionChancellor:\r
+        return BlackFairyRook;\r
+      case WhitePromotionArchbishop:\r
+        return WhiteFairyBishop;\r
+      case BlackPromotionArchbishop:\r
+        return BlackFairyBishop;\r
+#endif\r
+    }\r
+}\r
+\r
+ChessMove PromoCharToMoveType(whiteOnMove, promoChar)\r
+     int whiteOnMove;\r
+     int promoChar;\r
+{\r
+    if (whiteOnMove) {\r
+       switch (promoChar) {\r
+         case 'n':\r
+         case 'N':\r
+           return WhitePromotionKnight;\r
+         case 'b':\r
+         case 'B':\r
+           return WhitePromotionBishop;\r
+         case 'r':\r
+         case 'R':\r
+           return WhitePromotionRook;\r
+#ifdef FAIRY\r
+          case 'a':\r
+          case 'A':\r
+            return WhitePromotionArchbishop;\r
+          case 'c':\r
+          case 'C':\r
+            return WhitePromotionChancellor;\r
+#endif\r
+         case 'q':\r
+         case 'Q':\r
+           return WhitePromotionQueen;\r
+         case 'k':\r
+         case 'K':\r
+           return WhitePromotionKing;\r
+         case NULLCHAR:\r
+         default:\r
+           return NormalMove;\r
+       }\r
+    } else {\r
+       switch (promoChar) {\r
+         case 'n':\r
+         case 'N':\r
+           return BlackPromotionKnight;\r
+         case 'b':\r
+         case 'B':\r
+           return BlackPromotionBishop;\r
+         case 'r':\r
+         case 'R':\r
+           return BlackPromotionRook;\r
+#ifdef FAIRY\r
+          case 'a':\r
+          case 'A':\r
+            return BlackPromotionArchbishop;\r
+          case 'c':\r
+          case 'C':\r
+            return BlackPromotionChancellor;\r
+#endif\r
+         case 'q':\r
+         case 'Q':\r
+           return BlackPromotionQueen;\r
+         case 'k':\r
+         case 'K':\r
+           return BlackPromotionKing;\r
+         case NULLCHAR:\r
+         default:\r
+           return NormalMove;\r
+       }\r
+    }\r
+}\r
+\r
+char pieceToChar[] = {\r
+    'P', 'N', 'B', 'R', \r
+#ifdef FAIRY\r
+    'A', 'C', 'F', 'H', 'E', 'W', 'D', 'O', 'G', 'M',\r
+#endif\r
+    'Q', 'K', 'p', 'n', 'b', 'r', \r
+#ifdef FAIRY            \r
+    'a', 'c', 'f', 'h', 'e', 'w', 'd', 'o', 'g', 'm',\r
+#endif\r
+    'q', 'k', 'x'\r
+  };\r
+\r
+char PieceToChar(p)\r
+     ChessSquare p;\r
+{\r
+    return pieceToChar[(int) p];\r
+}\r
+\r
+ChessSquare CharToPiece(c)\r
+     int c;\r
+{    switch (c) {\r
+      default:\r
+      case 'x':        return EmptySquare;\r
+      case 'P':        return WhitePawn;\r
+      case 'R':        return WhiteRook;\r
+      case 'N':        return WhiteKnight;\r
+      case 'B':        return WhiteBishop;\r
+      case 'Q':        return WhiteQueen;\r
+      case 'K':        return WhiteKing;\r
+      case 'p':        return BlackPawn;\r
+      case 'r':        return BlackRook;\r
+      case 'n':        return BlackKnight;\r
+      case 'b':        return BlackBishop;\r
+      case 'q':        return BlackQueen;\r
+      case 'k':        return BlackKing;\r
+#ifdef FAIRY\r
+      case 'A': return WhiteCardinal;\r
+      case 'C': return WhiteMarshall;\r
+      case 'F': return WhiteFairyPawn;\r
+      case 'H': return WhiteFairyKnight;\r
+      case 'E': return WhiteFairyBishop;\r
+      case 'W': return WhiteFairyRook;\r
+      case 'D': return WhiteFairyCardinal;\r
+      case 'O': return WhiteFairyMarshall;\r
+      case 'G': return WhiteFairyQueen;\r
+      case 'M': return WhiteFairyKing;\r
+                \r
+      case 'a': return BlackCardinal;\r
+      case 'c': return BlackMarshall;\r
+      case 'f': return BlackFairyPawn;\r
+      case 'h': return BlackFairyKnight;\r
+      case 'e': return BlackFairyBishop;\r
+      case 'w': return BlackFairyRook;\r
+      case 'd': return BlackFairyCardinal;\r
+      case 'o': return BlackFairyMarshall;\r
+      case 'g': return BlackFairyQueen;\r
+      case 'm': return BlackFairyKing;\r
+                \r
+#endif\r
+    }\r
+}\r
+\r
+void CopyBoard(to, from)\r
+     Board to, from;\r
+{\r
+    int i, j;\r
+    \r
+    for (i = 0; i < BOARD_HEIGHT; i++)\r
+      for (j = 0; j < BOARD_WIDTH; j++)\r
+       to[i][j] = from[i][j];\r
+}\r
+\r
+int CompareBoards(board1, board2)\r
+     Board board1, board2;\r
+{\r
+    int i, j;\r
+    \r
+    for (i = 0; i < BOARD_HEIGHT; i++)\r
+      for (j = 0; j < BOARD_WIDTH; j++) {\r
+         if (board1[i][j] != board2[i][j])\r
+           return FALSE;\r
+    }\r
+    return TRUE;\r
+}\r
+\r
+\r
+/* Call callback once for each pseudo-legal move in the given\r
+   position, except castling moves. A move is pseudo-legal if it is\r
+   legal, or if it would be legal except that it leaves the king in\r
+   check.  In the arguments, epfile is EP_NONE if the previous move\r
+   was not a double pawn push, or the file 0..7 if it was, or\r
+   EP_UNKNOWN if we don't know and want to allow all e.p. captures.\r
+   Promotion moves generated are to Queen only.\r
+*/\r
+void GenPseudoLegal(board, flags, epfile, callback, closure)\r
+     Board board;\r
+     int flags;\r
+     int epfile;\r
+     MoveCallback callback;\r
+     VOIDSTAR closure;\r
+{\r
+    int rf, ff;\r
+    int i, j, d, s, fs, rs, rt, ft, m;\r
+\r
+    for (rf = 0; rf < BOARD_HEIGHT; rf++) \r
+      for (ff = 0; ff < BOARD_WIDTH; ff++) {\r
+         if (flags & F_WHITE_ON_MOVE) {\r
+             if (!WhitePiece(board[rf][ff])) continue;\r
+         } else {\r
+             if (!BlackPiece(board[rf][ff])) continue;\r
+         }\r
+          m = 0;\r
+         switch (board[rf][ff]) {\r
+           case EmptySquare:\r
+           default:\r
+             /* can't happen ([HGM] except for faries...) */\r
+             break;\r
+\r
+           case WhitePawn:\r
+#ifdef FAIRY\r
+              if(gameInfo.variant == VariantXiangqi) {\r
+                  /* [HGM] capture and move straight ahead in Xiangqi */\r
+                  if (rf < BOARD_HEIGHT-1 &&\r
+                           !SameColor(board[rf][ff], board[rf + 1][ff]) ) {\r
+                           callback(board, flags, NormalMove,\r
+                                    rf, ff, rf + 1, ff, closure);\r
+                  }\r
+                  /* and move sideways when across the river */\r
+                  for (s = -1; s <= 1; s += 2) {\r
+                      if (rf >= BOARD_HEIGHT>>1 &&\r
+                          ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                          !WhitePiece(board[rf][ff+s]) ) {\r
+                           callback(board, flags, NormalMove,\r
+                                    rf, ff, rf, ff+s, closure);\r
+                      }\r
+                  }\r
+                  break;\r
+              }\r
+#endif\r
+              if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) {\r
+                 callback(board, flags,\r
+                          rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
+                          rf, ff, rf + 1, ff, closure);\r
+             }\r
+             if (rf == 1 && board[2][ff] == EmptySquare &&\r
+                  gameInfo.variant != VariantShatranj && /* [HGM] */\r
+                  board[3][ff] == EmptySquare ) {\r
+                      callback(board, flags, NormalMove,\r
+                               rf, ff, 3, ff, closure);\r
+             }\r
+             for (s = -1; s <= 1; s += 2) {\r
+                 if (rf < BOARD_HEIGHT-1 && ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                     ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
+                      BlackPiece(board[rf + 1][ff + s]))) {\r
+                     callback(board, flags, \r
+                              rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove,\r
+                              rf, ff, rf + 1, ff + s, closure);\r
+                 }\r
+                 if (rf == BOARD_HEIGHT-4) {\r
+                     if (ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                         (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
+                          board[BOARD_HEIGHT-4][ff + s] == BlackPawn &&\r
+                          board[BOARD_HEIGHT-3][ff + s] == EmptySquare) {\r
+                         callback(board, flags, WhiteCapturesEnPassant,\r
+                                  rf, ff, 5, ff + s, closure);\r
+                     }\r
+                 }\r
+             }             \r
+             break;\r
+\r
+           case BlackPawn:\r
+#ifdef FAIRY\r
+              if(gameInfo.variant == VariantXiangqi) {\r
+                  /* [HGM] capture straight ahead in Xiangqi */\r
+                  if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) {\r
+                           callback(board, flags, NormalMove,\r
+                                    rf, ff, rf - 1, ff, closure);\r
+                  }\r
+                  /* and move sideways when across the river */\r
+                  for (s = -1; s <= 1; s += 2) {\r
+                      if (rf < BOARD_HEIGHT>>1 &&\r
+                          ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                          !BlackPiece(board[rf][ff+s]) ) {\r
+                           callback(board, flags, NormalMove,\r
+                                    rf, ff, rf, ff+s, closure);\r
+                      }\r
+                  }\r
+                  break;\r
+              }\r
+#endif\r
+             if (rf > 0 && board[rf - 1][ff] == EmptySquare) {\r
+                 callback(board, flags, \r
+                          rf == 1 ? BlackPromotionQueen : NormalMove,\r
+                          rf, ff, rf - 1, ff, closure);\r
+             }\r
+             if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare &&\r
+                  gameInfo.variant != VariantShatranj && /* [HGM] */\r
+                 board[BOARD_HEIGHT-4][ff] == EmptySquare) {\r
+                 callback(board, flags, NormalMove,\r
+                          rf, ff, BOARD_HEIGHT-4, ff, closure);\r
+             }\r
+             for (s = -1; s <= 1; s += 2) {\r
+                 if (rf > 0 && ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                     ((flags & F_KRIEGSPIEL_CAPTURE) ||\r
+                      WhitePiece(board[rf - 1][ff + s]))) {\r
+                     callback(board, flags, \r
+                              rf == 1 ? BlackPromotionQueen : NormalMove,\r
+                              rf, ff, rf - 1, ff + s, closure);\r
+                 }\r
+                 if (rf == 3) {\r
+                      if (ff + s >= 0 && ff + s < BOARD_WIDTH &&\r
+                         (epfile == ff + s || epfile == EP_UNKNOWN) &&\r
+                         board[3][ff + s] == WhitePawn &&\r
+                         board[2][ff + s] == EmptySquare) {\r
+                         callback(board, flags, BlackCapturesEnPassant,\r
+                                  rf, ff, 2, ff + s, closure);\r
+                     }\r
+                 }\r
+             }             \r
+             break;\r
+\r
+           case WhiteKnight:\r
+           case BlackKnight:\r
+            mounted:\r
+             for (i = -1; i <= 1; i += 2)\r
+               for (j = -1; j <= 1; j += 2)\r
+                 for (s = 1; s <= 2; s++) {\r
+                     rt = rf + i*s;\r
+                     ft = ff + j*(3-s);\r
+                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) continue;\r
+                     if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
+                     callback(board, flags, NormalMove,\r
+                              rf, ff, rt, ft, closure);\r
+                 }\r
+             break;\r
+#ifdef FAIRY\r
+            case WhiteFairyMarshall:\r
+            case BlackFairyMarshall:\r
+              for (d = 0; d <= 1; d++)\r
+                for (s = -1; s <= 1; s += 2) {\r
+                  m = 0;\r
+                 for (i = 1;; i++) {\r
+                     rt = rf + (i * s) * d;\r
+                     ft = ff + (i * s) * (1 - d);\r
+                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                      if (m == 0 && board[rt][ft] == EmptySquare)\r
+                                 callback(board, flags, NormalMove,\r
+                                          rf, ff, rt, ft, closure);\r
+                      if (m == 1 && board[rt][ft] != EmptySquare &&\r
+                          !SameColor(board[rf][ff], board[rt][ft]) )\r
+                                 callback(board, flags, NormalMove,\r
+                                          rf, ff, rt, ft, closure);\r
+                      if (board[rt][ft] != EmptySquare && m++) break;\r
+                  }\r
+                }\r
+             break;\r
+\r
+            case WhiteFairyRook:\r
+            case BlackFairyRook:\r
+              for (d = 0; d <= 1; d++)\r
+                for (s = -1; s <= 1; s += 2)\r
+                      rt = rf + s * d;\r
+                      ft = ff + s * (1 - d);\r
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH)\r
+                          && !SameColor(board[rf][ff], board[rt][ft]))\r
+                               callback(board, flags, NormalMove,\r
+                                        rf, ff, rt, ft, closure);\r
+             break;\r
+\r
+           case WhiteFairyBishop:\r
+           case BlackFairyBishop:\r
+                /* [HGM] support Shatranj pieces */\r
+                for (rs = -1; rs <= 1; rs += 2) \r
+                  for (fs = -1; fs <= 1; fs += 2) {\r
+                      rt = rf + 2 * rs;\r
+                      ft = ff + 2 * fs;\r
+                      if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH)\r
+                          && !SameColor(board[rf][ff], board[rt][ft]))\r
+                               callback(board, flags, NormalMove,\r
+                                        rf, ff, rt, ft, closure);\r
+                 }\r
+                break;\r
+\r
+            case WhiteCardinal:\r
+            case BlackCardinal:\r
+              m++;\r
+#endif\r
+           case WhiteBishop:\r
+           case BlackBishop:\r
+             for (rs = -1; rs <= 1; rs += 2) \r
+                for (fs = -1; fs <= 1; fs += 2) \r
+                 for (i = 1;; i++) {\r
+                     rt = rf + (i * rs);\r
+                     ft = ff + (i * fs);\r
+                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
+                     callback(board, flags, NormalMove,\r
+                              rf, ff, rt, ft, closure);\r
+                     if (board[rt][ft] != EmptySquare) break;\r
+                 }\r
+                if(m) goto mounted;\r
+             break;\r
+\r
+#ifdef FAIRY\r
+            case WhiteMarshall:\r
+            case BlackMarshall:\r
+              m++;\r
+#endif\r
+           case WhiteRook:\r
+           case BlackRook:\r
+              for (d = 0; d <= 1; d++)\r
+                for (s = -1; s <= 1; s += 2)\r
+                 for (i = 1;; i++) {\r
+                     rt = rf + (i * s) * d;\r
+                     ft = ff + (i * s) * (1 - d);\r
+                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                     if (SameColor(board[rf][ff], board[rt][ft])) break;\r
+                     callback(board, flags, NormalMove,\r
+                              rf, ff, rt, ft, closure);\r
+                     if (board[rt][ft] != EmptySquare) break;\r
+                 }\r
+                if(m) goto mounted;\r
+             break;\r
+\r
+           case WhiteQueen:\r
+           case BlackQueen:\r
+             for (rs = -1; rs <= 1; rs++) \r
+               for (fs = -1; fs <= 1; fs++) {\r
+                   if (rs == 0 && fs == 0) continue;\r
+                   for (i = 1;; i++) {\r
+                       rt = rf + (i * rs);\r
+                       ft = ff + (i * fs);\r
+                       if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                       if (SameColor(board[rf][ff], board[rt][ft])) break;\r
+                       callback(board, flags, NormalMove,\r
+                                rf, ff, rt, ft, closure);\r
+                       if (board[rt][ft] != EmptySquare) break;\r
+                   }\r
+               }\r
+             break;\r
+\r
+#ifdef FAIRY\r
+            case WhiteFairyPawn:\r
+            case BlackFairyPawn:\r
+                /* [HGM] support Shatranj pieces */\r
+                for (rs = -1; rs <= 1; rs += 2) \r
+                  for (fs = -1; fs <= 1; fs += 2) {\r
+                      rt = rf + rs;\r
+                      ft = ff + fs;\r
+                     if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) break;\r
+                      if (!SameColor(board[rf][ff], board[rt][ft]))\r
+                               callback(board, flags, NormalMove,\r
+                                        rf, ff, rt, ft, closure);\r
+                 }\r
+                break;\r
+\r
+            case WhiteFairyKing:\r
+            case BlackFairyKing:\r
+#endif\r
+           case WhiteKing:\r
+           case BlackKing:\r
+             for (i = -1; i <= 1; i++)\r
+               for (j = -1; j <= 1; j++) {\r
+                   if (i == 0 && j == 0) continue;\r
+                   rt = rf + i;\r
+                   ft = ff + j;\r
+                   if (rt < 0 || rt >= BOARD_HEIGHT || ft < 0 || ft >= BOARD_WIDTH) continue;\r
+                   if (SameColor(board[rf][ff], board[rt][ft])) continue;\r
+                   callback(board, flags, NormalMove,\r
+                            rf, ff, rt, ft, closure);\r
+               }\r
+             break;\r
+         }\r
+      }\r
+}\r
+\r
+\r
+typedef struct {\r
+    MoveCallback cb;\r
+    VOIDSTAR cl;\r
+} GenLegalClosure;\r
+\r
+extern void GenLegalCallback P((Board board, int flags, ChessMove kind,\r
+                               int rf, int ff, int rt, int ft,\r
+                               VOIDSTAR closure));\r
+\r
+void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
+     Board board;\r
+     int flags;\r
+     ChessMove kind;\r
+     int rf, ff, rt, ft;\r
+     VOIDSTAR closure;\r
+{\r
+    register GenLegalClosure *cl = (GenLegalClosure *) closure;\r
+\r
+    if (!(flags & F_IGNORE_CHECK) &&\r
+       CheckTest(board, flags, rf, ff, rt, ft,\r
+                 kind == WhiteCapturesEnPassant ||\r
+                 kind == BlackCapturesEnPassant)) return;\r
+    if (flags & F_ATOMIC_CAPTURE) {\r
+      if (board[rt][ft] != EmptySquare ||\r
+         kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {\r
+       int r, f;\r
+       ChessSquare king = (flags & F_WHITE_ON_MOVE) ? WhiteKing : BlackKing;\r
+       if (board[rf][ff] == king) return;\r
+       for (r = rt-1; r <= rt+1; r++) {\r
+         for (f = ft-1; f <= ft+1; f++) {\r
+           if (r >= 0 && r < BOARD_HEIGHT && f >= 0 && f < BOARD_WIDTH &&\r
+               board[r][f] == king) return;\r
+         }\r
+       }\r
+      }\r
+    }\r
+    cl->cb(board, flags, kind, rf, ff, rt, ft, cl->cl);\r
+}\r
+\r
+\r
+typedef struct {\r
+    int rf, ff, rt, ft;\r
+    ChessMove kind;\r
+} LegalityTestClosure;\r
+\r
+\r
+/* Like GenPseudoLegal, but (1) include castling moves, (2) unless\r
+   F_IGNORE_CHECK is set in the flags, omit moves that would leave the\r
+   king in check, and (3) if F_ATOMIC_CAPTURE is set in the flags, omit\r
+   moves that would destroy your own king.  The CASTLE_OK flags are\r
+   true if castling is not yet ruled out by a move of the king or\r
+   rook.  Return TRUE if the player on move is currently in check and\r
+   F_IGNORE_CHECK is not set.  [HGM] add castlingRights parameter */\r
+int GenLegal(board, flags, epfile, castlingRights, callback, closure)\r
+     Board board;\r
+     int flags;\r
+     int epfile;\r
+     char castlingRights[];\r
+     MoveCallback callback;\r
+     VOIDSTAR closure;\r
+{\r
+    GenLegalClosure cl;\r
+    int ff, ft;\r
+    int ignoreCheck = (flags & F_IGNORE_CHECK) != 0;\r
+\r
+    cl.cb = callback;\r
+    cl.cl = closure;\r
+    GenPseudoLegal(board, flags, epfile, GenLegalCallback, (VOIDSTAR) &cl);\r
+\r
+    if (!ignoreCheck &&\r
+       CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE;\r
+\r
+    /* Generate castling moves */\r
+    for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) {\r
+       if ((flags & F_WHITE_ON_MOVE) &&\r
+           (flags & F_WHITE_KCASTLE_OK) &&\r
+           board[0][ff] == WhiteKing &&\r
+           board[0][ff + 1] == EmptySquare &&\r
+           board[0][ff + 2] == EmptySquare &&\r
+           board[0][BOARD_WIDTH-3] == EmptySquare &&\r
+           board[0][BOARD_WIDTH-2] == EmptySquare &&\r
+           board[0][BOARD_WIDTH-1] == WhiteRook &&\r
+            castlingRights[0] >= 0 && /* [HGM] check rights */\r
+            ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
+            (ignoreCheck ||                             \r
+            (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) &&\r
+             !CheckTest(board, flags, 0, ff, 0, BOARD_WIDTH-3, FALSE) &&\r
+             !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) {\r
+\r
+           callback(board, flags,\r
+                    ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild,\r
+                    0, ff, 0, ff + ((BOARD_WIDTH+2)>>2), closure);\r
+       }\r
+       if ((flags & F_WHITE_ON_MOVE) &&\r
+           (flags & F_WHITE_QCASTLE_OK) &&\r
+           board[0][ff] == WhiteKing &&\r
+           board[0][ff - 1] == EmptySquare &&\r
+           board[0][ff - 2] == EmptySquare &&\r
+           board[0][2] == EmptySquare &&\r
+           board[0][1] == EmptySquare &&\r
+            board[0][0] == WhiteRook &&\r
+            castlingRights[1] >= 0 && /* [HGM] check rights */\r
+            ( castlingRights[2] == ff || castlingRights[6] == ff ) &&\r
+           (ignoreCheck ||\r
+            (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) &&\r
+             !CheckTest(board, flags, 0, ff, 0, 3,      FALSE) &&\r
+             !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) {\r
+\r
+           callback(board, flags,\r
+                    ff==BOARD_WIDTH>>1 ? WhiteQueenSideCastle : WhiteQueenSideCastleWild,\r
+                    0, ff, 0, ff - ((BOARD_WIDTH+2)>>2), closure);\r
+       }\r
+       if (!(flags & F_WHITE_ON_MOVE) &&\r
+           (flags & F_BLACK_KCASTLE_OK) &&\r
+           board[BOARD_HEIGHT-1][ff] == BlackKing &&\r
+           board[BOARD_HEIGHT-1][ff + 1] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][ff + 2] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][BOARD_WIDTH-3] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][BOARD_WIDTH-2] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][BOARD_WIDTH-1] == BlackRook &&\r
+            castlingRights[3] >= 0 && /* [HGM] check rights */\r
+            ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
+           (ignoreCheck ||\r
+            (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) &&\r
+             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_WIDTH-3, FALSE) &&\r
+             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) {\r
+\r
+           callback(board, flags,\r
+                    ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild,\r
+                    BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((BOARD_WIDTH+2)>>2), closure);\r
+       }\r
+       if (!(flags & F_WHITE_ON_MOVE) &&\r
+           (flags & F_BLACK_QCASTLE_OK) &&\r
+           board[BOARD_HEIGHT-1][ff] == BlackKing &&\r
+           board[BOARD_HEIGHT-1][ff - 1] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][ff - 2] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][2] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][1] == EmptySquare &&\r
+           board[BOARD_HEIGHT-1][0] == BlackRook &&\r
+            castlingRights[4] >= 0 && /* [HGM] check rights */\r
+            ( castlingRights[5] == ff || castlingRights[7] == ff ) &&\r
+           (ignoreCheck ||\r
+            (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) &&\r
+             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, 3,      FALSE) &&\r
+             !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE)))) {\r
+\r
+           callback(board, flags,\r
+                    ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild,\r
+                    BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - ((BOARD_WIDTH+2)>>2), closure);\r
+       }\r
+    }\r
+\r
+    /* PUSH Fabien */\r
+\r
+    /* generate all potential FRC castling moves (KxR), ignoring flags */\r
+    /* [HGM] Tord! Help requested! */\r
+\r
+    if ((flags & F_WHITE_ON_MOVE) != 0) {\r
+\r
+       for (ff = 1; ff < BOARD_WIDTH-1; ff++) {\r
+          if (board[0][ff] == WhiteKing) {\r
+             for (ft = 0; ft < BOARD_WIDTH; ft++) {\r
+                if (board[0][ft] == WhiteRook) {\r
+                   callback(board, flags, \r
+                            (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR,\r
+                            0, ff, 0, ft, closure);\r
+                }\r
+             }\r
+          }\r
+       }\r
+\r
+    } else {\r
+\r
+       for (ff = 1; ff < BOARD_WIDTH-1; ff++) {\r
+          if (board[BOARD_HEIGHT-1][ff] == BlackKing) {\r
+             for (ft = 0; ft < BOARD_WIDTH; ft++) {\r
+                if (board[BOARD_HEIGHT-1][ft] == BlackRook) {\r
+                   callback(board, flags, \r
+                            (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR,\r
+                            BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);\r
+                }\r
+             }\r
+          }\r
+       }\r
+    }\r
+\r
+    /* POP Fabien */\r
+\r
+    return FALSE;\r
+}\r
+\r
+\r
+typedef struct {\r
+    int rking, fking;\r
+    int check;\r
+} CheckTestClosure;\r
+\r
+\r
+extern void CheckTestCallback P((Board board, int flags, ChessMove kind,\r
+                                int rf, int ff, int rt, int ft,\r
+                                VOIDSTAR closure));\r
+\r
+\r
+void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
+     Board board;\r
+     int flags;\r
+     ChessMove kind;\r
+     int rf, ff, rt, ft;\r
+     VOIDSTAR closure;\r
+{\r
+    register CheckTestClosure *cl = (CheckTestClosure *) closure;\r
+\r
+    if (rt == cl->rking && ft == cl->fking) cl->check++;\r
+}\r
+\r
+\r
+/* If the player on move were to move from (rf, ff) to (rt, ft), would\r
+   he leave himself in check?  Or if rf == -1, is the player on move\r
+   in check now?  enPassant must be TRUE if the indicated move is an\r
+   e.p. capture.  The possibility of castling out of a check along the\r
+   back rank is not accounted for (i.e., we still return nonzero), as\r
+   this is illegal anyway.  Return value is the number of times the\r
+   king is in check. */ \r
+int CheckTest(board, flags, rf, ff, rt, ft, enPassant)\r
+     Board board;\r
+     int flags;\r
+     int rf, ff, rt, ft, enPassant;\r
+{\r
+    CheckTestClosure cl;\r
+    ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;\r
+    ChessSquare captured = EmptySquare;\r
+    /*  Suppress warnings on uninitialized variables    */\r
+\r
+    if (rf >= 0) {\r
+       if (enPassant) {\r
+           captured = board[rf][ft];\r
+           board[rf][ft] = EmptySquare;\r
+       } else {\r
+           captured = board[rt][ft];\r
+       }\r
+       board[rt][ft] = board[rf][ff];\r
+       board[rf][ff] = EmptySquare;\r
+    }\r
+\r
+    /* For compatibility with ICS wild 9, we scan the board in the\r
+       order a1, a2, a3, ... b1, b2, ..., h8 to find the first king,\r
+       and we test only whether that one is in check. */\r
+    cl.check = 0;\r
+    for (cl.fking = 0; cl.fking < BOARD_WIDTH; cl.fking++)\r
+       for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) {\r
+         if (board[cl.rking][cl.fking] == king) {\r
+             GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1,\r
+                            CheckTestCallback, (VOIDSTAR) &cl);\r
+             goto undo_move;  /* 2-level break */\r
+         }\r
+      }\r
+\r
+  undo_move:\r
+\r
+    if (rf >= 0) {\r
+       board[rf][ff] = board[rt][ft];\r
+       if (enPassant) {\r
+           board[rf][ft] = captured;\r
+           board[rt][ft] = EmptySquare;\r
+       } else {\r
+           board[rt][ft] = captured;\r
+       }\r
+    }\r
+\r
+    return cl.check;\r
+}\r
+\r
+\r
+extern void LegalityTestCallback P((Board board, int flags, ChessMove kind,\r
+                                   int rf, int ff, int rt, int ft,\r
+                                   VOIDSTAR closure));\r
+\r
+void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
+     Board board;\r
+     int flags;\r
+     ChessMove kind;\r
+     int rf, ff, rt, ft;\r
+     VOIDSTAR closure;\r
+{\r
+    register LegalityTestClosure *cl = (LegalityTestClosure *) closure;\r
+\r
+    if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft)\r
+      cl->kind = kind;\r
+}\r
+\r
+ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, promoChar)\r
+     Board board;\r
+     int flags, epfile;\r
+     int rf, ff, rt, ft, promoChar;\r
+     char castlingRights[];\r
+{\r
+    LegalityTestClosure cl;\r
+    \r
+    cl.rf = rf;\r
+    cl.ff = ff;\r
+    cl.rt = rt;\r
+    cl.ft = ft;\r
+    cl.kind = IllegalMove;\r
+    GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl);\r
+    if (promoChar != NULLCHAR && promoChar != 'x') {\r
+       if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) {\r
+           cl.kind = \r
+             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0, promoChar);\r
+       } else {\r
+           cl.kind = IllegalMove;\r
+       }\r
+    }\r
+    return cl.kind;\r
+}\r
+\r
+typedef struct {\r
+    int count;\r
+} MateTestClosure;\r
+\r
+extern void MateTestCallback P((Board board, int flags, ChessMove kind,\r
+                               int rf, int ff, int rt, int ft,\r
+                               VOIDSTAR closure));\r
+\r
+void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
+     Board board;\r
+     int flags;\r
+     ChessMove kind;\r
+     int rf, ff, rt, ft;\r
+     VOIDSTAR closure;\r
+{\r
+    register MateTestClosure *cl = (MateTestClosure *) closure;\r
+\r
+    cl->count++;\r
+}\r
+\r
+/* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */\r
+int MateTest(board, flags, epfile, castlingRights)\r
+     Board board;\r
+     int flags, epfile;\r
+     char castlingRights[];\r
+{\r
+    MateTestClosure cl;\r
+    int inCheck;\r
+\r
+    cl.count = 0;\r
+    inCheck = GenLegal(board, flags, epfile, castlingRights, MateTestCallback, (VOIDSTAR) &cl);\r
+    if (cl.count > 0) {\r
+       return inCheck ? MT_CHECK : MT_NONE;\r
+    } else {\r
+       return inCheck ? MT_CHECKMATE : MT_STALEMATE;\r
+    }\r
+}\r
+\r
+     \r
+extern void DisambiguateCallback P((Board board, int flags, ChessMove kind,\r
+                                   int rf, int ff, int rt, int ft,\r
+                                   VOIDSTAR closure));\r
+\r
+void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
+     Board board;\r
+     int flags;\r
+     ChessMove kind;\r
+     int rf, ff, rt, ft;\r
+     VOIDSTAR closure;\r
+{\r
+    register DisambiguateClosure *cl = (DisambiguateClosure *) closure;\r
+\r
+    if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) &&\r
+       (cl->rfIn == -1 || cl->rfIn == rf) &&\r
+       (cl->ffIn == -1 || cl->ffIn == ff) &&\r
+       (cl->rtIn == -1 || cl->rtIn == rt) &&\r
+       (cl->ftIn == -1 || cl->ftIn == ft)) {\r
+\r
+       cl->count++;\r
+       cl->piece = board[rf][ff];\r
+       cl->rf = rf;\r
+       cl->ff = ff;\r
+       cl->rt = rt;\r
+       cl->ft = ft;\r
+       cl->kind = kind;\r
+    }\r
+}\r
+\r
+void Disambiguate(board, flags, epfile, closure)\r
+     Board board;\r
+     int flags, epfile;\r
+     DisambiguateClosure *closure;\r
+{\r
+    int illegal = 0;\r
+    closure->count = 0;\r
+    closure->rf = closure->ff = closure->rt = closure->ft = 0;\r
+    closure->kind = ImpossibleMove;\r
+    GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure);\r
+    if (closure->count == 0) {\r
+       /* See if it's an illegal move due to check */\r
+        illegal = 1;\r
+        GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights, DisambiguateCallback,\r
+                (VOIDSTAR) closure);   \r
+       if (closure->count == 0) {\r
+           /* No, it's not even that */\r
+           return;\r
+       }\r
+    }\r
+    if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') {\r
+       if (closure->kind == WhitePromotionQueen\r
+           || closure->kind == BlackPromotionQueen) {\r
+           closure->kind = \r
+             PromoCharToMoveType((flags & F_WHITE_ON_MOVE) != 0,\r
+                                 closure->promoCharIn);\r
+       } else {\r
+           closure->kind = IllegalMove;\r
+       }\r
+    }\r
+    closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind)));\r
+    if (closure->promoChar == 'x') closure->promoChar = NULLCHAR;\r
+    if (closure->count > 1) {\r
+       closure->kind = AmbiguousMove;\r
+    }\r
+    if (illegal) {\r
+       /* Note: If more than one illegal move matches, but no legal\r
+          moves, we return IllegalMove, not AmbiguousMove.  Caller\r
+          can look at closure->count to detect this.\r
+       */\r
+       closure->kind = IllegalMove;\r
+    }\r
+}\r
+\r
+\r
+typedef struct {\r
+    /* Input */\r
+    ChessSquare piece;\r
+    int rf, ff, rt, ft;\r
+    /* Output */\r
+    ChessMove kind;\r
+    int rank;\r
+    int file;\r
+    int either;\r
+} CoordsToAlgebraicClosure;\r
+\r
+extern void CoordsToAlgebraicCallback P((Board board, int flags,\r
+                                        ChessMove kind, int rf, int ff,\r
+                                        int rt, int ft, VOIDSTAR closure));\r
+\r
+void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure)\r
+     Board board;\r
+     int flags;\r
+     ChessMove kind;\r
+     int rf, ff, rt, ft;\r
+     VOIDSTAR closure;\r
+{\r
+    register CoordsToAlgebraicClosure *cl =\r
+      (CoordsToAlgebraicClosure *) closure;\r
+\r
+    if (rt == cl->rt && ft == cl->ft &&\r
+       board[rf][ff] == cl->piece) {\r
+       if (rf == cl->rf) {\r
+           if (ff == cl->ff) {\r
+               cl->kind = kind; /* this is the move we want */\r
+           } else {\r
+               cl->file++; /* need file to rule out this move */\r
+           }\r
+       } else {\r
+           if (ff == cl->ff) {\r
+               cl->rank++; /* need rank to rule out this move */\r
+           } else {\r
+               cl->either++; /* rank or file will rule out this move */\r
+           }\r
+       }           \r
+    }\r
+}\r
+\r
+/* Convert coordinates to normal algebraic notation.\r
+   promoChar must be NULLCHAR or 'x' if not a promotion.\r
+*/\r
+ChessMove CoordsToAlgebraic(board, flags, epfile,\r
+                           rf, ff, rt, ft, promoChar, out)\r
+     Board board;\r
+     int flags, epfile;\r
+     int rf, ff, rt, ft;\r
+     int promoChar;\r
+     char out[MOVE_LEN];\r
+{\r
+    ChessSquare piece;\r
+    ChessMove kind;\r
+    char *outp = out;\r
+    CoordsToAlgebraicClosure cl;\r
+    \r
+    if (rf == DROP_RANK) {\r
+       /* Bughouse piece drop */\r
+       *outp++ = ToUpper(PieceToChar((ChessSquare) ff));\r
+       *outp++ = '@';\r
+       *outp++ = ft + 'a';\r
+        if(rt+ONE <= '9')\r
+           *outp++ = rt + ONE;\r
+        else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
+       *outp = NULLCHAR;\r
+       return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop;\r
+    }\r
+\r
+    if (promoChar == 'x') promoChar = NULLCHAR;\r
+    piece = board[rf][ff];\r
+    switch (piece) {\r
+      case WhitePawn:\r
+      case BlackPawn:\r
+        kind = LegalityTest(board, flags, epfile, initialRights, rf, ff, rt, ft, promoChar);\r
+       if (kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
+           /* Keep short notation if move is illegal only because it\r
+               leaves the player in check, but still return IllegalMove */\r
+            kind = LegalityTest(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
+                              rf, ff, rt, ft, promoChar);\r
+           if (kind == IllegalMove) break;\r
+           kind = IllegalMove;\r
+       }\r
+       /* Pawn move */\r
+       *outp++ = ff + 'a';\r
+        if (ff == ft && board[rt][ft] == EmptySquare) { /* [HGM] Xiangqi has straight noncapts! */\r
+           /* Non-capture; use style "e5" */\r
+            if(rt+ONE <= '9')\r
+               *outp++ = rt + ONE;\r
+            else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
+       } else {\r
+           /* Capture; use style "exd5" */\r
+            if(gameInfo.variant != VariantXiangqi || board[rt][ft] != EmptySquare )\r
+            *outp++ = 'x';  /* [HGM] Xiangqi has sideway noncaptures across river! */\r
+           *outp++ = ft + 'a';\r
+            if(rt+ONE <= '9')\r
+               *outp++ = rt + ONE;\r
+            else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
+       }\r
+       /* Use promotion suffix style "=Q" */\r
+       if (promoChar != NULLCHAR && promoChar != 'x') {\r
+           *outp++ = '=';\r
+           *outp++ = ToUpper(promoChar);\r
+       }\r
+       *outp = NULLCHAR;\r
+       return kind;\r
+\r
+       \r
+      case WhiteKing:\r
+      case BlackKing:\r
+        /* Fabien moved code: FRC castling first (if KxR), wild castling second */\r
+       /* Code added by Tord:  FRC castling. */\r
+       if((piece == WhiteKing && board[rt][ft] == WhiteRook) ||\r
+          (piece == BlackKing && board[rt][ft] == BlackRook)) {\r
+         if(ft > ff) strcpy(out, "O-O"); else strcpy(out, "O-O-O");\r
+            return LegalityTest(board, flags, epfile, initialRights,\r
+                               rf, ff, rt, ft, promoChar);\r
+       }\r
+       /* End of code added by Tord */\r
+       /* Test for castling or ICS wild castling */\r
+       /* Use style "O-O" (oh-oh) for PGN compatibility */\r
+       else if (rf == rt &&\r
+           rf == ((piece == WhiteKing) ? 0 : BOARD_HEIGHT-1) &&\r
+           ((ff == BOARD_WIDTH>>1 && (ft == 2 || ft == BOARD_WIDTH-2)) ||\r
+            (ff == (BOARD_WIDTH-1)>>1 && (ft == 1 || ft == BOARD_WIDTH-3)))) {\r
+           if(ft==1 || ft==BOARD_WIDTH-2)\r
+               strcpy(out, "O-O");\r
+            else\r
+               strcpy(out, "O-O-O");\r
+\r
+           /* This notation is always unambiguous, unless there are\r
+              kings on both the d and e files, with "wild castling"\r
+              possible for the king on the d file and normal castling\r
+              possible for the other.  ICS rules for wild 9\r
+              effectively make castling illegal for either king in\r
+              this situation.  So I am not going to worry about it;\r
+              I'll just generate an ambiguous O-O in this case.\r
+           */\r
+            return LegalityTest(board, flags, epfile, initialRights,\r
+                               rf, ff, rt, ft, promoChar);\r
+       }\r
+\r
+       /* else fall through */\r
+      default:\r
+       /* Piece move */\r
+       cl.rf = rf;\r
+       cl.ff = ff;\r
+       cl.rt = rt;\r
+       cl.ft = ft;\r
+       cl.piece = piece;\r
+       cl.kind = IllegalMove;\r
+       cl.rank = cl.file = cl.either = 0;\r
+        GenLegal(board, flags, epfile, initialRights,\r
+                CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
+\r
+       if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {\r
+           /* Generate pretty moves for moving into check, but\r
+              still return IllegalMove.\r
+           */\r
+            GenLegal(board, flags|F_IGNORE_CHECK, epfile, initialRights,\r
+                    CoordsToAlgebraicCallback, (VOIDSTAR) &cl);\r
+           if (cl.kind == IllegalMove) break;\r
+           cl.kind = IllegalMove;\r
+       }\r
+\r
+       /* Style is "Nf3" or "Nxf7" if this is unambiguous,\r
+          else "Ngf3" or "Ngxf7",\r
+          else "N1f3" or "N5xf7",\r
+          else "Ng1f3" or "Ng5xf7".\r
+       */\r
+       *outp++ = ToUpper(PieceToChar(piece));\r
+       \r
+       if (cl.file || (cl.either && !cl.rank)) {\r
+           *outp++ = ff + 'a';\r
+       }\r
+       if (cl.rank) {\r
+            if(rf+ONE <= '9')\r
+                *outp++ = rf + ONE;\r
+            else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
+       }\r
+\r
+       if(board[rt][ft] != EmptySquare)\r
+         *outp++ = 'x';\r
+\r
+       *outp++ = ft + 'a';\r
+        if(rt+ONE <= '9')\r
+           *outp++ = rt + ONE;\r
+        else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
+       *outp = NULLCHAR;\r
+       return cl.kind;\r
+       \r
+#ifdef FAIRY\r
+      /* [HGM] Always long notation for fairies, don't know how they move */\r
+      case WhiteFairyRook:\r
+      case BlackFairyRook:\r
+      case WhiteFairyKnight:\r
+      case BlackFairyKnight:\r
+      case WhiteFairyQueen:\r
+      case BlackFairyQueen:\r
+#endif\r
+      case EmptySquare:\r
+       /* Moving a nonexistent piece */\r
+       break;\r
+    }\r
+    \r
+    /* Not a legal move, even ignoring check.\r
+       If there was a piece on the from square, \r
+       use style "Ng1g3" or "Ng1xe8";\r
+       if there was a pawn or nothing (!),\r
+       use style "g1g3" or "g1xe8".  Use "x"\r
+       if a piece was on the to square, even\r
+       a piece of the same color.\r
+    */\r
+    outp = out;\r
+    if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {\r
+       *outp++ = ToUpper(PieceToChar(piece));\r
+    }\r
+    *outp++ = ff + 'a';\r
+    if(rf+ONE <= '9')\r
+       *outp++ = rf + ONE;\r
+    else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }\r
+    if (board[rt][ft] != EmptySquare) *outp++ = 'x';\r
+    *outp++ = ft + 'a';\r
+    if(rt+ONE <= '9')\r
+       *outp++ = rt + ONE;\r
+    else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }\r
+    /* Use promotion suffix style "=Q" */\r
+    if (promoChar != NULLCHAR && promoChar != 'x') {\r
+       *outp++ = '=';\r
+       *outp++ = ToUpper(promoChar);\r
+    }\r
+    *outp = NULLCHAR;\r
+\r
+    return IllegalMove;\r
+}\r
+\r
+\r