/* GNU Chess 5.0 - move.c - make and unmake moves code
   Copyright (c) 1999-2002 Free Software Foundation, Inc.

   GNU Chess is based on the two research programs 
   Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.

   GNU Chess 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, or (at your option)
   any later version.

   GNU Chess 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 GNU Chess; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact Info: 
     bug-gnu-chess@gnu.org
     cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
*/
/*
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "util.h"
#include "eval.h"
#include "bitboard.h"
#include "move.h"
#include "movelist.h"
#include "material.h"
#include "square.h"
#include "piece.h"
#include "atak.h"
#include "genmove.h"
#include "swap.h"
#include "magic.h"


#define NOHASH (ULL(0xdeafbeefdeadbeef))

char *AlgbrMove (int move);


int MoveConnected(int firstmove, int secondmove){
    int firstto,secondto,firstfrom,secondfrom;
    firstto=TOSQ(firstmove);
    firstfrom=FROMSQ(firstmove);
    secondto=TOSQ(secondmove);
    secondfrom=FROMSQ(secondmove);
    if(firstto==secondfrom){
    	return true;
    }
    if(bitboards.BitPosArray[firstfrom] & bitboards.FromToRay[secondfrom][secondto]){
	return true;
    }
    return false;
}

int MoveAvoidThreat(int threat, int defence){
    int threatto,defenceto,threatfrom,defencefrom;
    threatto=TOSQ(threat);
    threatfrom=FROMSQ(threat);
    defenceto=TOSQ(defence);
    defencefrom=FROMSQ(defence);
    // capture threatening piece or block.
    if(bitboards.BitPosArray[defenceto] & bitboards.FromToRay[threatto][threatfrom]){
	return true;
    }
    // block pawn (TODO: check that threat is pawn move)
    if(threatto==defenceto){
	return true;
    }
    // threat is capture and threatened piece moves away
    if(threatto==defencefrom){
	return true;
    }
    return false;
}

void MoveMake(board_t *board, int move){
  undo_t undo[1];
  MoveMakeS(board,&move,undo);
}

void MoveMakeS(board_t *board, int *move, undo_t *undo)
/**************************************************************************
 *
 *  To make a move on the board and update the various game information.
 *
 **************************************************************************/
{
   BitBoard *a;
   int f, t, fpiece, tpiece; 
   int rookf, rookt, epsq, sq;
   int xside;
   int side;

   ASSERT(BoardValidate(board)==0);
   ASSERT(!board->xin_check);
   ASSERT(MoveIsPseudoLegal(board,*move));
#ifdef DEBUG
   memcpy(&undo->board,board,sizeof(board_t));
   ASSERT(BoardIsEqual(board,&undo->board)==0)
#endif 

   side=board->side;

   xside = 1^side;
   f = FROMSQ(*move);
   t = TOSQ(*move);
   fpiece = board->cboard[f];
   tpiece = board->cboard[t];
   a = &board->b[side][fpiece];
   CLEARBIT (*a, f);
   SETBIT (*a, t);
   board->cboard[f] = empty;
   board->cboard[t] = fpiece;
   undo->phase=board->phase;
   undo->epsq = board->ep; 
   undo->bflag = board->flag;
   undo->Game50 = board->Game50;
   undo->mvboard = board->Mvboard[t];
   undo->phashkey = board->PawnHashKey;
   undo->hashkey = board->HashKey;
   undo->in_check=board->in_check;
   undo->xin_check=board->xin_check;
   if(board->GameCnt-board->Game50<MAXSTACK){
     undo->stack=board->stack[board->GameCnt-board->Game50];
     board->stack[board->GameCnt-board->Game50]=board->HashKey;
   }else{
     undo->stack=NOHASH;
   }
   board->GameCnt++;
   board->Mvboard[t] = board->Mvboard[f]+1; 
   board->Mvboard[f] = 0;
   if (board->ep > -1){
      board->HashKey ^= ephash[board->ep];
   }
   board->HashKey ^= hashcode[side][fpiece][f];
   board->HashKey ^= hashcode[side][fpiece][t];
   if (fpiece == king){
      board->king[side] = t;
   }
   if (fpiece == pawn) {
      board->PawnHashKey ^= hashcode[side][pawn][f];
      board->PawnHashKey ^= hashcode[side][pawn][t];
   }

   if (tpiece != 0){		/* Capture */
      CLEARBIT (board->b[xside][tpiece], t);
      *move |= (tpiece << 15);
      board->HashKey ^= hashcode[xside][tpiece][t];
      if (tpiece == pawn){
         board->PawnHashKey ^= hashcode[xside][pawn][t];
      }
      board->material[xside] -= Value[tpiece];
      board->material_index -= MaterialDelta[xside][tpiece];
      if (tpiece != pawn){
         board->pmaterial[xside] -= Value[tpiece];
      }
   }

   if (*move & PROMOTION){ 	/* Promotion */ 
      SETBIT (board->b[side][PROMOTEPIECE (*move)], t);
      CLEARBIT (*a, t);
      board->cboard[t] = PROMOTEPIECE (*move);
      board->HashKey ^= hashcode[side][pawn][t];
      board->HashKey ^= hashcode[side][board->cboard[t]][t];
      board->PawnHashKey ^= hashcode[side][pawn][t];
      board->material[side] += (Value[board->cboard[t]] - ValueP);

      board->material_index += MaterialDelta[side][board->cboard[t]] - MaterialDelta[side][pawn];

      board->pmaterial[side] += Value[board->cboard[t]];
   }

   if (*move & ENPASSANT){	/* En passant */
      epsq = board->ep + (side == white ? - 8 : 8);
      CLEARBIT (board->b[xside][pawn], epsq);
      board->cboard[epsq] = empty;
      board->HashKey ^= hashcode[xside][pawn][epsq];
      board->PawnHashKey ^= hashcode[xside][pawn][epsq];
      board->material[xside] -= ValueP;

      board->material_index -= MaterialDelta[xside][pawn];

   }
   if (*move & (CAPTURE | CASTLING) || fpiece == pawn){
      board->Game50 = board->GameCnt;
   }
   if (*move & CASTLING){ 	/* Castling */
       if (t & 0x04){		/* King side */
         rookf = t + 1;
         rookt = t - 1;
       }else{			/* Queen side */
	   rookf = t - 2;
	   rookt = t + 1;
       }
      a = &board->b[side][rook];
      CLEARBIT (*a, rookf);
      SETBIT (*a, rookt);
      board->cboard[rookf] = empty;
      board->cboard[rookt] = rook;
      board->Mvboard[rookf] = 0;
      board->Mvboard[rookt] = 1;
      board->HashKey ^= hashcode[side][rook][rookf];
      board->HashKey ^= hashcode[side][rook][rookt];
      board->castled[side] = true;
   }

   /* If king or rook move, clear castle flag. */
   if (side == white) {
      if (fpiece == king && board->flag & WCASTLE) {
	  if (board->flag & WKINGCASTLE){
            board->HashKey ^= WKCastlehash;
	  }
	  if (board->flag & WQUEENCASTLE){
            board->HashKey ^= WQCastlehash;
	  }
         board->flag &= ~WCASTLE;
      }else if (fpiece == rook){
         if (f == H1){
	    if (board->flag & WKINGCASTLE)
               board->HashKey ^= WKCastlehash;
	    board->flag &= ~WKINGCASTLE;
	 }else if (f == A1){
	     if (board->flag & WQUEENCASTLE){
               board->HashKey ^= WQCastlehash;
	     }
	    board->flag &= ~WQUEENCASTLE;
	 }
      }
      if (tpiece == rook) {
         if (t == H8){
	     if (board->flag & BKINGCASTLE){
	       board->HashKey ^= BKCastlehash;
	     }
	    board->flag &= ~BKINGCASTLE;
         }else if (t == A8){
	    if (board->flag & BQUEENCASTLE)
	       board->HashKey ^= BQCastlehash;
	    board->flag &= ~BQUEENCASTLE;
	 }
      }
   }else{
      if (fpiece == king && board->flag & BCASTLE) {
	  if (board->flag & BKINGCASTLE){
	    board->HashKey ^= BKCastlehash;
	  }
	  if (board->flag & BQUEENCASTLE){
	    board->HashKey ^= BQCastlehash;
	  }
         board->flag &= ~BCASTLE;
      }else if (fpiece == rook){
         if (f == H8){
	     if (board->flag & BKINGCASTLE){
	       board->HashKey ^= BKCastlehash;
	     }
	    board->flag &= ~BKINGCASTLE;
         }else if (f == A8){
	     if (board->flag & BQUEENCASTLE){
	       board->HashKey ^= BQCastlehash;
	     }
	    board->flag &= ~BQUEENCASTLE;
	 }
      }if (tpiece == rook){
         if (t == H1){
	     if (board->flag & WKINGCASTLE){
               board->HashKey ^= WKCastlehash;
	     }
	    board->flag &= ~WKINGCASTLE;
	 } else if (t == A1)  {
	     if (board->flag & WQUEENCASTLE){
               board->HashKey ^= WQCastlehash;
	     }
	    board->flag &= ~WQUEENCASTLE;
	 }
      } 
   }


   /* If pawn move 2 squares, set ep passant square. */
   //   if (fpiece == pawn && abs(f-t) == 16){
   //    sq = (f + t) / 2;
   //   board->ep = sq;
   //    board->HashKey ^= ephash[sq];
   //}else{
   //   board->ep = -1;
   //}

   /* 
    *  Set ep passant square only if applicable
    *  This deviates from the fen standard but
    *  many programs sin in this way.
    */
   if (fpiece == pawn && 
       abs(f-t) == 16 &&
       (board->b[xside][pawn] & bitboards.MoveArray[ptype[side]][(sq=(f+t)/2)])
       ){
       board->ep = sq;
       board->HashKey ^= ephash[sq];
   }else{
      board->ep = -1;
   }

   board->side = xside;
   board->HashKey ^= Sidehash;


   BoardUpdateFriends (board);

   board->phase=Material[board->material_index].phase;
   board->in_check=SqAtakd (board,board->king[board->side], 1^board->side);
   board->xin_check=SqAtakd (board,board->king[1^board->side], board->side);

   undo->move=*move;

   ASSERT(BoardValidate(board)==0);   

   return;
}


void MoveUnMakeS (board_t *board, undo_t *undo)
/****************************************************************************
 *
 *  To unmake a move on the board and update the various game information.
 *  Note that if side is black, then black is about to move, but we will be
 *  undoing a move by white, not black.
 *
 ****************************************************************************/
{
   BitBoard *a;
   int f, t, fpiece, cpiece;   
   int rookf, rookt, epsq;
   int side;
   int xside;
   int move;

   ASSERT(BoardValidate(board)==0);   

   side=board->side;
   move=undo->move;

   side = 1^side;
   xside = 1^side;
   f = FROMSQ(move);
   t = TOSQ(move);
   fpiece = board->cboard[t];
   cpiece = CAPTUREPIECE (move);
   a = &board->b[side][fpiece];
   CLEARBIT (*a, t);
   SETBIT (*a, f);   
   board->cboard[f] = board->cboard[t];
   board->cboard[t] = empty;
   board->Mvboard[f] = board->Mvboard[t]-1;
   board->Mvboard[t] = undo->mvboard;
   if (fpiece == king)
      board->king[side] = f;
   
   /* if capture, put back the captured piece */
   if (move & CAPTURE) {
      SETBIT (board->b[xside][cpiece], t);  
      board->cboard[t] = cpiece; 
      board->material[xside] += Value[cpiece];  

      board->material_index += MaterialDelta[xside][cpiece];

      if (cpiece != pawn){
         board->pmaterial[xside] += Value[cpiece];  
      }
   }

   /* Undo promotion */
   if (move & PROMOTION)
   {
      CLEARBIT (*a, f);
      SETBIT (board->b[side][pawn], f);  
      board->cboard[f] = pawn;
      board->material[side] += (ValueP - Value[PROMOTEPIECE (move)]); 

      board->material_index += MaterialDelta[side][pawn]-MaterialDelta[side][PROMOTEPIECE(move)];

      board->pmaterial[side] -= Value[PROMOTEPIECE (move)];
   }

   /* Undo enpassant */
   if (move & ENPASSANT)
   {
      epsq = (side == white ? undo->epsq - 8 : undo->epsq + 8);
      SETBIT (board->b[xside][pawn], epsq); 
      board->cboard[epsq] = pawn;
      board->material[xside] += ValueP;  

      board->material_index += MaterialDelta[xside][pawn];

   }   

   /* if castling, undo rook move */
   if (move & CASTLING) {
       if (t & 0x04){		/* King side */
         rookf = t + 1;
         rookt = t - 1;
       }else{			/* Queen side */
         rookf = t - 2;
         rookt = t + 1;
      }
      a = &board->b[side][rook];
      CLEARBIT (*a, rookt);
      SETBIT (*a, rookf); 
      board->cboard[rookf] = rook;
      board->cboard[rookt] = empty;
      board->Mvboard[rookf] = 0;
      board->Mvboard[rookt] = 0;
      board->castled[side] = false;
   }

   BoardUpdateFriends (board);
   board->side = side;
   board->phase=undo->phase;
   board->ep = undo->epsq;
   board->flag = undo->bflag;  
   board->HashKey = undo->hashkey;
   board->PawnHashKey = undo->phashkey;
   board->Game50 = undo->Game50;
   board->GameCnt--;
   board->in_check=undo->in_check;
   board->xin_check=undo->xin_check;
   if(undo->stack!=NOHASH){
     board->stack[board->GameCnt-board->Game50]=undo->stack;
   }
   ASSERT(BoardValidate(board)==0);
   ASSERT(BoardIsEqual(&undo->board,board)==0);
   return;
}


void MoveToSAN (board_t *board, int move, char *SAN)
/****************************************************************************
 *
 *  Convert the move to a SAN format.  
 *
 ****************************************************************************/
{
   int side;
   int piece, ambiguous;
   int f, t;
   BitBoard b;
   leaf *node1;
   char *s;
   movelist_t movelist[1];
   undo_t undo[1];

   if(move & NULLMOVE){
     strcpy(SAN,"null");
     return;
   }

   if(move==NOMOVE){
     strcpy(SAN,"nomove");
     return;
   }

   ASSERT(BoardValidate(board)==0);
   ASSERT(MoveIsPseudoLegal(board,move));
   GenPseudoMoves(board, movelist);

   side = board->side;
   s = SAN;
   f = FROMSQ(move);
   t = TOSQ(move);

   /* Check some special moves like castling */
   if (move & CASTLING)
   {
      if (t == 6 || t == 62)
         strcpy (s, "O-O");
      else
	 strcpy (s, "O-O-O");
      return;
   }
 
/****************************************************************************
 *
 *  Here split the code into 2 parts for clarity sake.  First part deals 
 *  with pawn moves only, 2nd part only piece moves.  However before doing 
 *  that, see if the move is ambiguous.
 *
 ****************************************************************************/

   /*  AMBIGUITY CHECK  */
   piece = board->cboard[f];
   side = board->side;
   b = board->b[side][piece];
   ambiguous = false;

   node1 = movelist->moves;
   if (nbits (b) > 1)
   {
      /* 
       *  Scan the movelist to see if another same-type piece is
       *  also moving to that particular to-square.
       */

     for (node1 = movelist->moves; node1 < movelist->moves+movelist->gencnt; node1++)
      {
         if (FROMSQ(node1->move) == f)
            continue;                   /* original piece, skip */
         if (TOSQ(node1->move) != t)
            continue;                   /* diff to-square, skip */
         if (board->cboard[FROMSQ(node1->move)] != piece)
            continue;                   /* diff piece   */
         ambiguous = true;
	 break;
      }
   }

   if (piece == pawn)
   {
      /* Capture or enpassant */
      if (board->cboard[t] != 0 || board->ep == t)
      {
         *s++ = algbrfile [FILE_ (f)];
	 *s++ = 'x';
      }
      strcpy (s, algbr[t]);
      s += 2;

      /* Promotion */
      if (move & PROMOTION)
      {
         *s++ = '=';
         *s++ = notation[PROMOTEPIECE (move)];
      }
   }
   else	/* its not pawn */
   {
      *s++ = notation[piece];
      if (ambiguous)
      {
         if (FILE_ (f) == FILE_ (FROMSQ(node1->move)))
            *s++ = algbrrank[RANK (f)];
	 else
	    *s++ = algbrfile[FILE_ (f)];
      }
      if (board->cboard[t] != 0)		/* capture */
         *s++ = 'x'; 
      strcpy (s, algbr[t]);
      s += 2;
   }

   /* See if it is a checking or mating move */
   MoveMakeS (board, &move, undo);
   if (SqAtakd (board,board->king[1^side], side))
   {
      GenPseudoCheckEscapes (board,movelist);
      if (movelist->gencnt == 0)
         *s++ = '#';
      else
         *s++ = '+';
   }
   MoveUnMakeS (board, undo); 

   *s = '\0';
   return;
}


#define ASCIITOFILE(a) ((a) - 'a')
#define ASCIITORANK(a) ((a) - '1')
#define ASCIITOSQ(a,b) (ASCIITOFILE(a)) + (ASCIITORANK(b)) * 8
#define ATOH(a) ((a) >= 'a' && (a) <= 'h')
#define ITO8(a) ((a) >= '1' && (a) <= '8')
#define PIECE(a) ((a)=='R' || (a)=='B' || (a)=='N' || (a)=='Q' || (a)=='K')

inline int piece_id(const char c)
{
/* Given c, what is the piece id.  This only takes one char, which
 * isn't enough to handle two-character names (common in Russian text
 * and old English notation that used Kt), but we're not supposed to
 * see such text here anyway.  This will
 * accept "P" for pawn, and many lowercase chars (but not "b" for Bishop). */
   switch (c)
   {
      case 'n':
      case 'N':
         return knight;
      case 'B':
         return bishop;
      case 'r':
      case 'R':
         return rook;
      case 'q':
      case 'Q':
         return queen;
      case 'k':
      case 'K':
         return king;
      case 'p':
      case 'P':
         return pawn;
   }
   return empty;
}

// Look for things that ressemble a move so that we can generate
// illegal move messages.

int MoveLookAlike (char *s){
  if(ATOH(s[0]) && ITO8(s[1])) return true; // d4 (LAN or SAN)
  if(PIECE(s[0]) && s[1]=='x') return true; // Nx 
  if(PIECE(s[0]) && ATOH(s[1])) return true; // Nd 
  if(PIECE(s[0]) && ITO8(s[1])) return true; // N4 
  if(ATOH(s[0]) && s[1]=='x') return true;  // dx 
  if(s[0]=='o' && s[1]=='-') return true;  // o-
  if(s[0]=='0' && s[1]=='-') return true;  // 0- 
  if(s[0]=='O' && s[1]=='-') return true;  // O- 
  return false;
}

void MoveFromString (board_t *board, int *move, char *s)
/*************************************************************************
 *
 *  This routine takes a string and check to see if it is a legal move.
 *  Note.  At the moment, we accept 2 types of moves notation.
 *  1.  e2e4 format.   2. SAN format. (e4)
 *
 **************************************************************************/
{
   short f, t, side, rank, file, fileto;
   short piece, piece2, kount;
   char promote;
   char mvstr[MAXSTR], *p;
   BitBoard b, b2;
   leaf *n1, *n2, *ret;
   movelist_t movelist[1];
   int err=0;

   GenMoves (board,movelist);   
   side = board->side;

   /************************************************************************
    * The thing to do now is to clean up the move string.  This
    * gets rid of things like 'x', '+', '=' and so forth.
    ************************************************************************/
   p = mvstr;
   do
   {
      if (*s != 'x' && *s != '+' && *s != '=' && !isspace(*s))
         *p++ = *s; 
   } while (*s++ != '\0' );

   /* Flush castles that check */
   if (mvstr[strlen(mvstr)-1] == '+' || mvstr[strlen(mvstr)-1] == '#' ||
       mvstr[strlen(mvstr)-1] == '=') mvstr[strlen(mvstr)-1] = '\000'; 

   /* Check for castling */
   if (strcmp (mvstr, "O-O") == 0 || strcmp (mvstr, "o-o") == 0 || 
       strcmp (mvstr, "0-0") == 0)
   {
      if (side == white)
      {
         f = 4; t = 6;
      }
      else 
      {
	 f = 60; t = 62;
      }
      ret=IsInMoveList (movelist,f, t, ' ');
      if(!ret){
	err=9;
      }
      goto fini;
   
   }

   if (strcmp (mvstr, "O-O-O") == 0 || strcmp (mvstr, "o-o-o") == 0 ||
       strcmp (mvstr, "0-0-0") == 0)
   {
      if (side == white)
      {
         f = 4; t = 2;
      }
      else
      {
         f = 60; t = 58;
      }
      ret=IsInMoveList (movelist, f, t, ' ');
      if(!ret){
	err=10;
      }
      goto fini;
   }

   /*  Test to see if it is e2e4 type notation */
   if (ATOH (mvstr[0]) && ITO8 (mvstr[1]) && ATOH (mvstr[2]) &&
	ITO8 (mvstr[3]))
   {
      f = ASCIITOSQ (mvstr[0], mvstr[1]);
      t = ASCIITOSQ (mvstr[2], mvstr[3]);
      piece = (strlen (mvstr) == 5 ? mvstr[4] : ' ');
      ret=IsInMoveList (movelist, f, t, piece);
      if(!ret){
	err=11;
      }
      goto fini;
   }


   /***********************************************************************
    *  Its a SAN notation move.  More headache!  
    *  We generate all the legal moves and start comparing them with
    *  the input move.
    ***********************************************************************/
   if (ATOH (mvstr[0]))	/* pawn move */
   {
      if (ITO8 (mvstr[1]))					/* e4 type */
      {
	 t = ASCIITOSQ (mvstr[0], mvstr[1]);
         f = t + (side == white ? -8 : 8);
         /* Add Sanity Check */
         if ( f > 0 && f < 64 ) {
	   if (bitboards.BitPosArray[f] & board->b[side][pawn])
           {
	     if (mvstr[2] != '\0'){ 

	       ret=IsInMoveList (movelist,f, t, mvstr[2]);
	       if(!ret){
		 err=12;
	       }
	       goto fini;
	     }else{
	       ret=IsInMoveList (movelist, f, t, ' ');
	       if(!ret){
		 err=14;
	       }
	       goto fini;
	     }
           }
           f = t + (side == white ? -16 : 16);
           if ( f > 0 && f < 64 ) {
	     if (bitboards.BitPosArray[f] & board->b[side][pawn]){

	       ret=IsInMoveList (movelist, f, t, ' ');
	       if(!ret){
		 err=15;
	       }
	       goto fini;
	     }
	   } /* End bound check +/- 16 */
	 } /* End bound check +/- 8 */
        }
      else if (ATOH (mvstr[1]) && ITO8 (mvstr[2]))		/* ed4 type */
      {
	 t = ASCIITOSQ (mvstr[1], mvstr[2]);
	 rank = ASCIITORANK (mvstr[2]) + (side == white ? -1 : 1);
         f = rank * 8 + ASCIITOFILE (mvstr[0]);
         piece = (strlen (mvstr) == 4 ? mvstr[3] : ' ');

	 ret=IsInMoveList (movelist, f, t, piece);
	 if(!ret){
	   err=16;
	 }
	 goto fini;
      }
      else if (ATOH (mvstr[1]))					/* ed type */
      {
         file = ASCIITOFILE (mvstr[0]);
         fileto = ASCIITOFILE (mvstr[1]);
	 b = board->b[side][pawn] & bitboards.FileBit[file];
	 if (side == white)
	    b = b >> (fileto < file ? 7 : 9);
         else
	    b = b << (fileto < file ? 9 : 7);
         if (board->ep > -1)
	    b = b & (board->friends[1^side] | bitboards.BitPosArray[board->ep]);
         else
	    b = b & (board->friends[1^side]);
         switch (nbits (b))
	 {
	    case 0  : 
	              err=1;
	              ret=(leaf *) NULL;          
		      goto fini;
	    case 1  : t = leadz (b);
	    	      f = t - (side == white ? 8 : -8) + (file - fileto);
         	      piece = (strlen (mvstr) == 3 ? mvstr[2] : ' ');

		      ret=IsInMoveList (movelist, f, t, piece);
		      if(!ret){
			err=8;
		      }
		      goto fini;
	    default : 
	              Output ("Ambiguous move: %s %s\n",s,mvstr);
                      err=2;
		      ret=(leaf *) NULL;
		      goto fini;
	 }
      } 

   } 
   else	if ((piece = piece_id(mvstr[0])) != empty &&
            (piece_id(mvstr[1]) == empty))	/* Is a piece move */
   {
      /* Since piece_id accepts P as pawns, this will correctly
       * handle malformed commands like Pe4 */

      b = board->b[side][piece];
      t = -1;
      if (ITO8 (mvstr[1]))				/* N1d2 type move */
      {
         rank = ASCIITORANK (mvstr[1]);
	 b &= bitboards.RankBit[rank];
	 t = ASCIITOSQ (mvstr[2], mvstr[3]);
      }
      else if (ATOH (mvstr[1]) && ATOH (mvstr[2]))	/* Nbd2 type move */
      {
         file = ASCIITOFILE (mvstr[1]);
	 b &= bitboards.FileBit[file];
	 t = ASCIITOSQ (mvstr[2], mvstr[3]);
      }
      else if (ATOH (mvstr[1]) && ITO8 (mvstr[2]))	/* Nd2 type move */
      {
	 t = ASCIITOSQ (mvstr[1], mvstr[2]);
      }

      kount = 0;
      n1 = n2 = (leaf *) NULL;
      while (b)
      {
         f = leadz (b);
 	 CLEARBIT (b, f);
	 if ((n1 = IsInMoveList (movelist, f, t, ' ')) != (leaf *) NULL )
	 {
	    n2 = n1;
	    kount++;
	 }
      }
      if (kount > 1)
      {
	 Output ("Ambiguous move: %s %s\n",s,mvstr);
         err=3;
	 ret=(leaf *) NULL;
	 goto fini;
      } 
      else if (kount == 0){
        err=4;
	ret=(leaf *) NULL;
	goto fini;
      }else{
	ret=n2;
	if(!ret){
	  err=17;
	}
	goto fini;
      }
   }
   else	if (((piece = piece_id(mvstr[0])) != empty) &&
            ((piece2 = piece_id(mvstr[1])) != empty) &&
	    ( (mvstr[2] == '\0') ||
	      ((piece_id(mvstr[2]) != empty) && mvstr[3] == '\0')))
   { /* KxP format */
      promote = ' ';
      if (piece_id(mvstr[2] != empty)) {
          promote = mvstr[2];
      }
      kount = 0;
      n1 = n2 = (leaf *) NULL;
      b = board->b[side][piece];
      while (b)
      {
         f = leadz (b);
 	 CLEARBIT (b, f);
         b2 = board->b[1^side][piece2];
	 while (b2)
	 {
           t = leadz (b2);
 	   CLEARBIT (b2, t);
	   if ((n1 = IsInMoveList (movelist, f, t, promote)) != (leaf *) NULL)
	   {
	     n2 = n1;
	     kount++;
	     Output("Y  ");
	   }
	   else Output("N  ");
	 }
      }
      if (kount > 1)
      {
	 Output ("Ambiguous move: %s %s\n",s,mvstr);
         err=5;
	 ret=(leaf *)NULL;
	 goto fini;
      } 
      else if (kount == 0){
	err=6;
	ret=(leaf *)NULL;
	goto fini;
      }else{
	ret=n2;
	if(!ret){
	  err=18;
	}
	goto fini;
      }
   }

   /* Fall through.  Nothing worked, return that no move was performed. */
   err=7;
   ret=(leaf *) NULL;

 fini:
   if(ret){
     *move=ret->move;
   }else{
       //     OutputConsole("Move parsing error=%d\n",err);
       //     BoardShow(board);
     *move=NOMOVE;
   }
}


leaf * IsInMoveList (movelist_t *movelist, int f, int t, char piece)
/**************************************************************************
 *
 *  Checks to see if from and to square can be found in the movelist
 *  and is legal.
 *
 **************************************************************************/
{
   leaf *node;


   for (node = movelist->moves; node < movelist->moves+movelist->gencnt; node++)
   {
      if ((int) (node->move & 0x0FFF) == MOVE(f,t)  && 
	toupper(piece) == notation[PROMOTEPIECE (node->move)])
         return (node);
   }
   return ((leaf *) NULL);
}


int MoveIsPseudoLegal (board_t *board, int move)
/*****************************************************************************
 *
 *  Check that a move is pseudo legal on the current board.  
 *  Perform some preliminary sanity checks.
 *  1.  If from square is emtpy, illegal.
 *  2.  Piece not of right color.
 *  3.  To square is friendly, illegal.
 *  4.  Promotion move or enpassant, so piece must be pawn.
 *  5.  Castling move, piece must be king.
 *  Note that MoveIsPseudoLegal() no longer cares about if a move will place the
 *  king in check.  This will be caught by the Search().
 *
 *****************************************************************************/
{
   int side;
   int f, t, piece;
   BitBoard blocker, enemy;

   f = FROMSQ(move); 
   t = TOSQ(move);

   /*  Empty from square  */
   if (board->cboard[f] == empty)
      return (false);

   /*  Piece is not right color  */
   side = board->side;
   if (!(bitboards.BitPosArray[f] & board->friends[side]))
      return (false);

   /*  TO square is a friendly piece, so illegal move  */
   if (bitboards.BitPosArray[t] & board->friends[side])
      return (false);

   piece = board->cboard[f];
   /*  If promotion move, piece must be pawn */
   if ((move & (PROMOTION | ENPASSANT)) && piece != pawn)
      return (false);

   /*  If enpassant, then the enpassant square must be correct */
   if ((move & ENPASSANT) && t != board->ep)
      return (false);

   /*  If castling, then make sure its the king */
   if ((move & CASTLING) && piece != king)
      return (false); 

   blocker = board->blocker;
   /*  Pawn moves need to be handle specially  */
   if (piece == pawn)
   {
      if ((move & ENPASSANT) && board->ep > -1)
         enemy = board->friends[1^side] | bitboards.BitPosArray[board->ep];
      else
         enemy = board->friends[1^side];
      if (side == white)
      {
         if (!(bitboards.MoveArray[pawn][f] & bitboards.BitPosArray[t] & enemy) &&
             !(t - f == 8 && board->cboard[t] == empty) &&
             !(t - f == 16 && RANK(f) == 1 && !(bitboards.FromToRay[f][t] & blocker)))
	    return (false);
      }
      else if (side == black)
      {
         if (!(bitboards.MoveArray[bpawn][f] & bitboards.BitPosArray[t] & enemy) &&
             !(t - f == -8 && board->cboard[t] == empty) &&
             !(t - f == -16 && RANK(f) == 6 && !(bitboards.FromToRay[f][t] & blocker)))
	    return (false);
      }
      // Check the promotion flag! 
      // This was a serious bug where some killers
      // would be considered legal when the weren't
      if (side==white){
	if((move & PROMOTION) && (t<=55)){
	  return(false);
	}
	if(!(move & PROMOTION) && (t>55)){
	  return(false);
	} 
      }else {  // side is black
	if((move & PROMOTION) && (t>=8)){
	  return(false);
	}
	if(!(move & PROMOTION) && (t<8)){
	  return(false);
	} 
      }
   }
   /*  King moves are also special, especially castling  */
   else if (piece == king)
   {
      if (side == white)
      {
         if (!(bitboards.MoveArray[piece][f] & bitboards.BitPosArray[t]) &&
	     !(f == E1 && t == G1 && board->flag & WKINGCASTLE &&
	       !(bitboards.FromToRay[E1][G1] & blocker) && !SqAtakd(board,E1,black) &&
	       !SqAtakd(board,F1,black) && !SqAtakd(board,G1,black) ) &&
	     !(f == E1 && t == C1 && board->flag & WQUEENCASTLE &&
	       !(bitboards.FromToRay[E1][B1] & blocker) && !SqAtakd(board,E1,black) &&
	       !SqAtakd(board,D1,black) && !SqAtakd(board,C1,black)))
            return (false);
      }
      if (side == black)
      {
         if (!(bitboards.MoveArray[piece][f] & bitboards.BitPosArray[t]) &&
	     !(f == E8 && t == G8 && board->flag & BKINGCASTLE &&
	       !(bitboards.FromToRay[E8][G8] & blocker) && !SqAtakd(board,E8,white) &&
	       !SqAtakd(board,F8,white) && !SqAtakd(board,G8,white) ) &&
	     !(f == E8 && t == C8 && board->flag & BQUEENCASTLE &&
	       !(bitboards.FromToRay[E8][B8] & blocker) && !SqAtakd(board,E8,white) &&
	       !SqAtakd(board,D8,white) && !SqAtakd(board,C8,white)))
            return (false);
      }
   }
   else 
   {
      if (!(bitboards.MoveArray[piece][f] & bitboards.BitPosArray[t]))
         return (false);
   }

   /*  If there is a blocker on the path from f to t, illegal move  */
   if (slider[piece])
   {
      if (bitboards.FromToRay[f][t] & bitboards.NotBitPosArray[t] & blocker)
         return (false);
   }

   return (true);
}

unsigned int MoveClassifier(board_t *board, int move){
    unsigned int ret=0;
    int t,f,side,xside,pawn_move;
    BitBoard bt;
    t=TOSQ(move);
    f=FROMSQ(move);
    bt=bitboards.BitPosArray[t];
    side=board->side;
    xside=1^side;
    pawn_move=(board->cboard[f]==pawn);
    if(board->cboard[t]!=0){
	ret|=CLASSCAPTURE;
    }
    /* en passant */
    if(pawn_move && ((bt & bitboards.FileBit[FILE_(f)])==NULLBITBOARD)){
	ret|=CLASSCAPTURE;
    }
    if(pawn_move && (bt & bitboards.RankBit[rank8[side]])){
	ret|=CLASSPROMOTION;
    }
    if(pawn_move && (bt & bitboards.RankBit[rank7[side]])){
	ret|=CLASS7RANK;
    }
    if(pawn_move && (bt & bitboards.RankBit[rank6[side]])){
	ret|=CLASS6RANK;
    }
    if(pawn_move && !(ret & CLASSPROMOTION) && 
       ((board->b[xside][pawn] & bitboards.PassedPawnMask[side][t])==NULLBITBOARD)){
	ret|=CLASSPASSEDPAWN;
    }
    //    if(SwapOff(board,move)<0){
    //	ret|=CLASSNEGATIVESWAPOFF;
    //}
    if(SwapOff(board,move)>=ValueB){
    	ret|=CLASSPOSITIVESWAPOFF;
    }
    return ret;
       
}


void MoveToLAN(int move, char *LAN)
/*****************************************************************************
 *
 *  Convert an int move format to algebraic format of g1f3.
 *
 *****************************************************************************/
{
   int f, t;

   f = FROMSQ(move);
   t = TOSQ(move);
   if(move==NULLMOVE){
     strcpy(LAN,"null");
     return;
   }

   if(move==NOMOVE){
       strcpy(LAN,"nomove");
       return;
   }

   strcpy (LAN, algbr[f]);
   strcpy (LAN+2, algbr[t]);
   if (move & PROMOTION) {
        LAN[4] = lnotation[PROMOTEPIECE (move)];
	LAN[5] = '\0';
   } else {
       LAN[4] = '\0';
   }
 }

char *AlgbrMove (int move)
/*****************************************************************************
 *
 *  Keep this one around for debugging
 *
 *****************************************************************************/
{
   static char s[6];
   MoveToLAN(move, s);
   return s;
}


