#include "chess.h"
 
#include "data.h"
 
/* last modified 02/24/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   InputMove() is responsible for converting a move from a text string to    *
 
 *   the internal move format.  It allows the so-called "reduced algebraic     *
 
 *   move format" which makes the origin square optional unless required for   *
 
 *   clarity.  It also accepts as little as required to remove ambiguity from  *
 
 *   the move, by using GenerateMoves() to produce a set of legal moves that   *
 
 *   the text can be applied against to eliminate those moves not intended.    *
 
 *   Hopefully, only one move will remain after the elimination and legality   *
 
 *   checks.                                                                   *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int InputMove(TREE * RESTRICT tree, int ply, int wtm, int silent,
 
    int ponder_list, char *text) {
 
  unsigned moves[220], *mv, *mvp, *goodmove = 0;
 
  int piece = -1, capture, promote, give_check;
 
  int ffile, frank, tfile, trank;
 
  int current, i, nleft;
 
  char *goodchar, *tc;
 
  char movetext[128];
 
  static const char pieces[15] =
 
      { ' ', ' ', 'P', 'p', 'N', 'n', 'B', 'b', 'R', 'r',
 
    'Q', 'q', 'K', 'k', '\0'
 
  };
 
  static const char pro_pieces[15] =
 
      { ' ', ' ', 'P', 'p', 'N', 'n', 'B', 'b', 'R', 'r', 'Q', 'q',
 
    'K', 'k', '\0'
 
  };
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First, we need to strip off the special characters for  *
 
 *  check, mate, bad move, good move, and such that might   *
 
 *  come from a PGN input file.                             *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    *tc = 0;
 
    *tc = 0;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Check for full coordinate input (f1e1) and handle that  *
 
 *  if needed.                                              *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    return 0;
 
  if ((text[0] >= 'a') && (text[0] <= 'h') && (text[1] >= '1')
 
      && (text[1] <= '8') && (text[2] >= 'a') && (text[2] <= 'h')
 
      && (text[3] >= '1') && (text[3] <= '8'))
 
    return InputMoveICS(tree, ply, wtm, silent, ponder_list, text);
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Initialize move structure.  If we discover a parsing    *
 
 *  error, this will cause us to return a move of "0" to    *
 
 *  indicate some sort of error was detected.               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  tree->status[MAXPLY] = tree->status[ply];
 
  moves[0] = 0;
 
  piece = 0;
 
  capture = 0;
 
  promote = 0;
 
  give_check = 0;
 
  frank = -1;
 
  ffile = -1;
 
  trank = -1;
 
  tfile = -1;
 
  goodchar 
= strchr(movetext
, '#'); 
  if (goodchar)
 
    *goodchar = 0;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First we look for castling moves which are a special    *
 
 *  case with an unusual syntax compared to normal moves.   *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    piece = king;
 
    if (wtm) {
 
      ffile = 4;
 
      frank = 0;
 
      tfile = 6;
 
      trank = 0;
 
    } else {
 
      ffile = 4;
 
      frank = 7;
 
      tfile = 6;
 
      trank = 7;
 
    }
 
  } else if (!strcmp(movetext
, "o-o-o") || !strcmp(movetext
, "o-o-o+")  
      || !strcmp(movetext
, "O-O-O") || !strcmp(movetext
, "O-O-O+")  
      || !strcmp(movetext
, "0-0-0") || !strcmp(movetext
, "0-0-0+")) {  
    piece = king;
 
    if (wtm) {
 
      ffile = 4;
 
      frank = 0;
 
      tfile = 2;
 
      trank = 0;
 
    } else {
 
      ffile = 4;
 
      frank = 7;
 
      tfile = 2;
 
      trank = 7;
 
    }
 
  } else {
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  OK, it is not a castling move.  Check for two "b"       *
 
 *  characters which might be a piece (bishop) and a file   *
 
 *  (b-file).  The first "b" should be "B" but we allow     *
 
 *  this to make typing input simpler.                      *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    if ((movetext[0] == 'b') && (movetext[1] == 'b'))
 
      movetext[0] = 'B';
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Check to see if there is a "+" character which means    *
 
 *  that this move is a check.  We can use this to later    *
 
 *  eliminate all non-checking moves as possibilities.      *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      give_check = 1;
 
    }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If this is a promotion, indicated by an "=" in the      *
 
 *  text, we can pick up the promote-to piece and save it   *
 
 *  to use later when eliminating moves.                    *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      goodchar 
= strchr(movetext
, '='); 
      goodchar++;
 
      promote 
= (strchr(pro_pieces
, *goodchar
) - pro_pieces
) >> 1; 
    }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now for a kludge.  ChessBase (and others) can't follow  *
 
 *  the PGN standard of bxc8=Q for promotion, and instead   *
 
 *  will produce "bxc8Q" omitting the PGN-standard "="      *
 
 *  character.  We handle that here so that we can read     *
 
 *  their non-standard moves.                               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    else {
 
      char *prom 
= strchr(pro_pieces
, movetext
[strlen(movetext
) - 1]);  
 
 
      if (prom) {
 
        promote = (prom - pro_pieces) >> 1;
 
        movetext
[strlen(movetext
) - 1] = 0; 
      }
 
    }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Next we extract the last rank/file designators from the *
 
 *  text, since the destination is required for all valid   *
 
 *  non-castling moves.  Note that we might not have both a *
 
 *  rank and file but we must have at least one.            *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    current 
= strlen(movetext
) - 1; 
    trank = movetext[current] - '1';
 
    if ((trank >= 0) && (trank <= 7))
 
      movetext[current] = 0;
 
    else
 
      trank = -1;
 
    current 
= strlen(movetext
) - 1; 
    tfile = movetext[current] - 'a';
 
    if ((tfile >= 0) && (tfile <= 7))
 
      movetext[current] = 0;
 
    else
 
      tfile = -1;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  The first character is the moving piece, unless it is a *
 
 *  pawn.  In this case, the moving piece is omitted and we *
 
 *  know what it has to be.                                 *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if (strchr("  PpNnBBRrQqKk", *movetext
)) {  
        piece 
= (strchr(pieces
, movetext
[0]) - pieces
) >> 1; 
        for (i 
= 0; i 
< (int) strlen(movetext
); i
++)  
          movetext[i] = movetext[i + 1];
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  It is also possible that this move is a capture, which  *
 
 *  is indicated by a "x" between either the source and     *
 
 *  destination squares, or between the moving piece and    *
 
 *  the destination.                                        *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if ((strlen(movetext
)) && (movetext
[strlen(movetext
) - 1] == 'x')) {  
        capture = 1;
 
        movetext
[strlen(movetext
) - 1] = 0; 
      } else
 
        capture = 0;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  It is possible to have no source square, but we could   *
 
 *  have a complete algebraic square designation, or just   *
 
 *  rank or file, needed to disambiguate the move.          *
 
 *                                                          *
 
 ************************************************************
 
 */
 
        ffile = movetext[0] - 'a';
 
        if ((ffile < 0) || (ffile > 7)) {
 
          ffile = -1;
 
          frank = movetext[0] - '1';
 
          if ((frank < 0) || (frank > 7))
 
            piece = -1;
 
        } else {
 
            frank = movetext[1] - '1';
 
            if ((frank < 0) || (frank > 7))
 
              piece = -1;
 
          }
 
        }
 
      }
 
    }
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now for the easy part.  We first generate all moves if  *
 
 *  not pondering, or else use a pre-computed list of moves *
 
 *  (if pondering) since the board position is not correct  *
 
 *  for move input analysis.  We then loop through the list *
 
 *  of moves, using the information we extracted previously *
 
 *  , and eliminate all moves that are (a) the wrong piece  *
 
 *  type;  (b) wrong source or destination square;          *
 
 *  (c) wrong promotion type;  (d) should be a capture,     *
 
 *  check or promotion but is not, or vice-versa.           *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (!piece)
 
    piece = 1;
 
  if (!ponder_list) {
 
    mvp = GenerateCaptures(tree, MAXPLY, wtm, moves);
 
    mvp = GenerateNoncaptures(tree, MAXPLY, wtm, mvp);
 
  } else {
 
    for (i = 0; i < num_ponder_moves; i++)
 
      moves[i] = ponder_moves[i];
 
    mvp = moves + num_ponder_moves;
 
  }
 
  for (mv = &moves[0]; mv < mvp; mv++) {
 
    if (piece && (Piece(*mv) != piece))
 
      *mv = 0;
 
    if ((ffile >= 0) && (File(From(*mv)) != ffile))
 
      *mv = 0;
 
    if (capture && (!Captured(*mv)))
 
      *mv = 0;
 
    if (promote && (Promote(*mv) != promote))
 
      *mv = 0;
 
    if ((frank >= 0) && (Rank(From(*mv)) != frank))
 
      *mv = 0;
 
    if ((tfile >= 0) && (File(To(*mv)) != tfile))
 
      *mv = 0;
 
    if ((trank >= 0) && (Rank(To(*mv)) != trank))
 
      *mv = 0;
 
    if (!ponder_list && *mv) {
 
      MakeMove(tree, MAXPLY, wtm, *mv);
 
      if (Check(wtm) || (give_check && !Check(Flip(wtm)))) {
 
        UnmakeMove(tree, MAXPLY, wtm, *mv);
 
        *mv = 0;
 
      } else
 
        UnmakeMove(tree, MAXPLY, wtm, *mv);
 
    }
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Once we have completed eliminating incorrect moves, we  *
 
 *  hope to have exactly one move left.  If none or left,   *
 
 *  the entered move is illegal.  If more than one is left, *
 
 *  the move entered is ambiguous.  If appropriate, we      *
 
 *  output some sort of diagnostic message and then return. *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  nleft = 0;
 
  for (mv = &moves[0]; mv < mvp; mv++) {
 
    if (*mv) {
 
      nleft++;
 
      goodmove = mv;
 
    }
 
  }
 
  if (nleft == 1)
 
    return *goodmove;
 
  if (!silent) {
 
    if (nleft == 0)
 
      Print(4095, "Illegal move: %s\n", text);
 
    else if (piece < 0)
 
      Print(4095, "Illegal move (unrecognizable): %s\n", text);
 
    else
 
      Print(4095, "Illegal move (ambiguous): %s\n", text);
 
  }
 
  return 0;
 
}
 
 
 
/* last modified 02/24/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   InputMoveICS() is responsible for converting a move from the ics format   *
 
 *   [from][to][promote] to the program's internal format.                     *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int InputMoveICS(TREE * RESTRICT tree, int ply, int wtm, int silent,
 
    int ponder_list, char *text) {
 
  unsigned moves[220], *mv, *mvp, *goodmove = 0;
 
  int piece = -1, promote;
 
  int ffile, frank, tfile, trank;
 
  int i, nleft;
 
  char movetext[128];
 
  static const char pieces[15] =
 
      { ' ', ' ', 'P', 'p', 'N', 'n', 'B', 'b', 'R', 'r',
 
    'Q', 'q', 'K', 'k', '\0'
 
  };
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Initialize move structure.  If we discover a parsing    *
 
 *  error, this will cause us to return a move of "0" to    *
 
 *  indicate some sort of error was detected.               *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    return 0;
 
  tree->status[MAXPLY] = tree->status[ply];
 
  moves[0] = 0;
 
  promote = 0;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First we look for castling moves which are a special    *
 
 *  case with an unusual syntax compared to normal moves.   *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      || !strcmp(movetext
, "0-0")) {  
    piece = king;
 
    if (wtm) {
 
      ffile = 4;
 
      frank = 0;
 
      tfile = 6;
 
      trank = 0;
 
    } else {
 
      ffile = 4;
 
      frank = 7;
 
      tfile = 6;
 
      trank = 7;
 
    }
 
  } else if (!strcmp(movetext
, "o-o-o") || !strcmp(movetext
, "O-O-O")  
      || !strcmp(movetext
, "0-0-0")) {  
    piece = king;
 
    if (wtm) {
 
      ffile = 4;
 
      frank = 0;
 
      tfile = 2;
 
      trank = 0;
 
    } else {
 
      ffile = 4;
 
      frank = 7;
 
      tfile = 2;
 
      trank = 7;
 
    }
 
  } else {
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Next we extract both rank/file designators from the     *
 
 *  text, since the destination is required for all valid   *
 
 *  non-castling moves.                                     *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    ffile = movetext[0] - 'a';
 
    frank = movetext[1] - '1';
 
    tfile = movetext[2] - 'a';
 
    trank = movetext[3] - '1';
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  If this is a promotion, indicated by an "=" in the      *
 
 *  text, we can pick up the promote-to piece and save it   *
 
 *  to use later when eliminating moves.                    *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    if (movetext[4] == '=')
 
      promote 
= (strchr(pieces
, movetext
[5]) - pieces
) >> 1; 
    else if ((movetext[4] != 0) && (movetext[4] != ' '))
 
      promote 
= (strchr(pieces
, movetext
[4]) - pieces
) >> 1; 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now for the easy part.  We first generate all moves if  *
 
 *  not pondering, or else use a pre-computed list of moves *
 
 *  (if pondering) since the board position is not correct  *
 
 *  for move input analysis.  We then loop through the list *
 
 *  of moves, using the information we extracted previously *
 
 *  and eliminate all moves that are (a) the wrong piece    *
 
 *  type;  (b) wrong source or destination square;          *
 
 *  (c) wrong promotion type;  (d) should be a capture,     *
 
 *  check or promotion but is not or vice-versa.            *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (!ponder_list) {
 
    mvp = GenerateCaptures(tree, MAXPLY, wtm, moves);
 
    mvp = GenerateNoncaptures(tree, MAXPLY, wtm, mvp);
 
  } else {
 
    for (i = 0; i < num_ponder_moves; i++)
 
      moves[i] = ponder_moves[i];
 
    mvp = moves + num_ponder_moves;
 
  }
 
  for (mv = &moves[0]; mv < mvp; mv++) {
 
    if (Promote(*mv) != promote)
 
      *mv = 0;
 
    if (Rank(From(*mv)) != frank)
 
      *mv = 0;
 
    if (File(From(*mv)) != ffile)
 
      *mv = 0;
 
    if (Rank(To(*mv)) != trank)
 
      *mv = 0;
 
    if (File(To(*mv)) != tfile)
 
      *mv = 0;
 
    if (!ponder_list && *mv) {
 
      MakeMove(tree, MAXPLY, wtm, *mv);
 
      if (Check(wtm)) {
 
        UnmakeMove(tree, MAXPLY, wtm, *mv);
 
        *mv = 0;
 
      } else
 
        UnmakeMove(tree, MAXPLY, wtm, *mv);
 
    }
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Once we have completed eliminating incorrect moves, we  *
 
 *  hope to have exactly one move left.  If none or left,   *
 
 *  the entered move is illegal.  If more than one is left, *
 
 *  the move entered is ambiguous.  If appropriate, we      *
 
 *  output some sort of diagnostic message and then return. *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  nleft = 0;
 
  for (mv = &moves[0]; mv < mvp; mv++) {
 
    if (*mv) {
 
      nleft++;
 
      goodmove = mv;
 
    }
 
  }
 
  if (nleft == 1)
 
    return *goodmove;
 
  if (!silent) {
 
    if (nleft == 0)
 
      Print(4095, "Illegal move: %s\n", text);
 
    else if (piece < 0)
 
      Print(4095, "Illegal move (unrecognizable): %s\n", text);
 
    else
 
      Print(4095, "Illegal move (ambiguous): %s\n", text);
 
  }
 
  return 0;
 
}