💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › games › chessengines › crafty › input.c captured on 2021-12-17 at 13:26:06.

View Raw

More Information

-=-=-=-=-=-=-

#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.                             *
 *                                                          *
 ************************************************************
 */
  if ((tc = strchr(text, '!')))
    *tc = 0;
  if ((tc = strchr(text, '?')))
    *tc = 0;
/*
 ************************************************************
 *                                                          *
 *  Check for full coordinate input (f1e1) and handle that  *
 *  if needed.                                              *
 *                                                          *
 ************************************************************
 */
  if (strlen(text) == 0)
    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];
  strcpy(movetext, text);
  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.   *
 *                                                          *
 ************************************************************
 */
  if (!strcmp(movetext, "o-o") || !strcmp(movetext, "o-o+")
      || !strcmp(movetext, "O-O") || !strcmp(movetext, "O-O+")
      || !strcmp(movetext, "0-0") || !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, "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.      *
 *                                                          *
 ************************************************************
 */
    if (strchr(movetext, '+')) {
      *strchr(movetext, '+') = 0;
      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.                    *
 *                                                          *
 ************************************************************
 */
    if (strchr(movetext, '=')) {
      goodchar = strchr(movetext, '=');
      goodchar++;
      promote = (strchr(pro_pieces, *goodchar) - pro_pieces) >> 1;
      *strchr(movetext, '=') = 0;
    }
/*
 ************************************************************
 *                                                          *
 *  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;
    if (strlen(movetext)) {
/*
 ************************************************************
 *                                                          *
 *  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.          *
 *                                                          *
 ************************************************************
 */
      if (strlen(movetext)) {
        ffile = movetext[0] - 'a';
        if ((ffile < 0) || (ffile > 7)) {
          ffile = -1;
          frank = movetext[0] - '1';
          if ((frank < 0) || (frank > 7))
            piece = -1;
        } else {
          if (strlen(movetext) == 2) {
            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.               *
 *                                                          *
 ************************************************************
 */
  if (strlen(text) == 0)
    return 0;
  tree->status[MAXPLY] = tree->status[ply];
  strcpy(movetext, text);
  moves[0] = 0;
  promote = 0;
/*
 ************************************************************
 *                                                          *
 *  First we look for castling moves which are a special    *
 *  case with an unusual syntax compared to normal moves.   *
 *                                                          *
 ************************************************************
 */
  if (!strcmp(movetext, "o-o") || !strcmp(movetext, "O-O")
      || !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;
}