Esempio n. 1
0
 /** Remove pseudo-legal EP square if it is not legal, ie would leave king in check. */
 public static final void fixupEPSquare(Position pos) {
   int epSquare = pos.getEpSquare();
   if (epSquare >= 0) {
     ArrayList<Move> moves = MoveGen.instance.pseudoLegalMoves(pos);
     moves = MoveGen.removeIllegal(pos, moves);
     boolean epValid = false;
     for (Move m : moves) {
       if (m.to == epSquare) {
         if (pos.getPiece(m.from) == (pos.whiteMove ? Piece.WPAWN : Piece.BPAWN)) {
           epValid = true;
           break;
         }
       }
     }
     if (!epValid) pos.setEpSquare(-1);
   }
 }
Esempio n. 2
0
  /**
   * Convert a chess move string to a Move object. The string may specify any combination of
   * piece/source/target/promotion information as long as it matches exactly one valid move.
   */
  public static final Move stringToMove(Position pos, String strMove) {
    if (strMove.equals("--")) return new Move(0, 0, 0);

    strMove = strMove.replaceAll("=", "");
    strMove = strMove.replaceAll("\\+", "");
    strMove = strMove.replaceAll("#", "");
    boolean wtm = pos.whiteMove;

    MoveInfo info = new MoveInfo();
    boolean capture = false;
    if (strMove.equals("O-O") || strMove.equals("0-0") || strMove.equals("o-o")) {
      info.piece = wtm ? Piece.WKING : Piece.BKING;
      info.fromX = 4;
      info.toX = 6;
      info.fromY = info.toY = wtm ? 0 : 7;
      info.promPiece = Piece.EMPTY;
    } else if (strMove.equals("O-O-O") || strMove.equals("0-0-0") || strMove.equals("o-o-o")) {
      info.piece = wtm ? Piece.WKING : Piece.BKING;
      info.fromX = 4;
      info.toX = 2;
      info.fromY = info.toY = wtm ? 0 : 7;
      info.promPiece = Piece.EMPTY;
    } else {
      boolean atToSq = false;
      for (int i = 0; i < strMove.length(); i++) {
        char c = strMove.charAt(i);
        if (i == 0) {
          int piece = charToPiece(wtm, c);
          if (piece >= 0) {
            info.piece = piece;
            continue;
          }
        }
        int tmpX = c - 'a';
        if ((tmpX >= 0) && (tmpX < 8)) {
          if (atToSq || (info.fromX >= 0)) info.toX = tmpX;
          else info.fromX = tmpX;
        }
        int tmpY = c - '1';
        if ((tmpY >= 0) && (tmpY < 8)) {
          if (atToSq || (info.fromY >= 0)) info.toY = tmpY;
          else info.fromY = tmpY;
        }
        if ((c == 'x') || (c == '-')) {
          atToSq = true;
          if (c == 'x') capture = true;
        }
        if (i == strMove.length() - 1) {
          int promPiece = charToPiece(wtm, c);
          if (promPiece >= 0) {
            info.promPiece = promPiece;
          }
        }
      }
      if ((info.fromX >= 0) && (info.toX < 0)) {
        info.toX = info.fromX;
        info.fromX = -1;
      }
      if ((info.fromY >= 0) && (info.toY < 0)) {
        info.toY = info.fromY;
        info.fromY = -1;
      }
      if (info.piece < 0) {
        boolean haveAll =
            (info.fromX >= 0) && (info.fromY >= 0) && (info.toX >= 0) && (info.toY >= 0);
        if (!haveAll) info.piece = wtm ? Piece.WPAWN : Piece.BPAWN;
      }
      if (info.promPiece < 0) info.promPiece = Piece.EMPTY;
    }

    ArrayList<Move> moves = MoveGen.instance.pseudoLegalMoves(pos);
    moves = MoveGen.removeIllegal(pos, moves);

    ArrayList<Move> matches = new ArrayList<Move>(2);
    for (int i = 0; i < moves.size(); i++) {
      Move m = moves.get(i);
      int p = pos.getPiece(m.from);
      boolean match = true;
      if ((info.piece >= 0) && (info.piece != p)) match = false;
      if ((info.fromX >= 0) && (info.fromX != Position.getX(m.from))) match = false;
      if ((info.fromY >= 0) && (info.fromY != Position.getY(m.from))) match = false;
      if ((info.toX >= 0) && (info.toX != Position.getX(m.to))) match = false;
      if ((info.toY >= 0) && (info.toY != Position.getY(m.to))) match = false;
      if ((info.promPiece >= 0) && (info.promPiece != m.promoteTo)) match = false;
      if (match) {
        matches.add(m);
      }
    }
    int nMatches = matches.size();
    if (nMatches == 0) return null;
    else if (nMatches == 1) return matches.get(0);
    if (!capture) return null;
    Move move = null;
    for (int i = 0; i < matches.size(); i++) {
      Move m = matches.get(i);
      int capt = pos.getPiece(m.to);
      if (capt != Piece.EMPTY) {
        if (move == null) move = m;
        else return null;
      }
    }
    return move;
  }
Esempio n. 3
0
  private static final String moveToString(
      Position pos, Move move, boolean longForm, List<Move> moves) {
    if (move.equals(new Move(0, 0, 0))) return "--";
    StringBuilder ret = new StringBuilder();
    int wKingOrigPos = Position.getSquare(4, 0);
    int bKingOrigPos = Position.getSquare(4, 7);
    if (move.from == wKingOrigPos && pos.getPiece(wKingOrigPos) == Piece.WKING) {
      // Check white castle
      if (move.to == Position.getSquare(6, 0)) {
        ret.append("O-O");
      } else if (move.to == Position.getSquare(2, 0)) {
        ret.append("O-O-O");
      }
    } else if (move.from == bKingOrigPos && pos.getPiece(bKingOrigPos) == Piece.BKING) {
      // Check white castle
      if (move.to == Position.getSquare(6, 7)) {
        ret.append("O-O");
      } else if (move.to == Position.getSquare(2, 7)) {
        ret.append("O-O-O");
      }
    }
    if (ret.length() == 0) {
      int p = pos.getPiece(move.from);
      ret.append(pieceToChar(p));
      int x1 = Position.getX(move.from);
      int y1 = Position.getY(move.from);
      int x2 = Position.getX(move.to);
      int y2 = Position.getY(move.to);
      if (longForm) {
        ret.append((char) (x1 + 'a'));
        ret.append((char) (y1 + '1'));
        ret.append(isCapture(pos, move) ? 'x' : '-');
      } else {
        if (p == (pos.whiteMove ? Piece.WPAWN : Piece.BPAWN)) {
          if (isCapture(pos, move)) {
            ret.append((char) (x1 + 'a'));
          }
        } else {
          int numSameTarget = 0;
          int numSameFile = 0;
          int numSameRow = 0;
          int mSize = moves.size();
          for (int mi = 0; mi < mSize; mi++) {
            Move m = moves.get(mi);
            if ((pos.getPiece(m.from) == p) && (m.to == move.to)) {
              numSameTarget++;
              if (Position.getX(m.from) == x1) numSameFile++;
              if (Position.getY(m.from) == y1) numSameRow++;
            }
          }
          if (numSameTarget < 2) {
            // No file/row info needed
          } else if (numSameFile < 2) {
            ret.append((char) (x1 + 'a')); // Only file info needed
          } else if (numSameRow < 2) {
            ret.append((char) (y1 + '1')); // Only row info needed
          } else {
            ret.append((char) (x1 + 'a')); // File and row info needed
            ret.append((char) (y1 + '1'));
          }
        }
        if (isCapture(pos, move)) {
          ret.append('x');
        }
      }
      ret.append((char) (x2 + 'a'));
      ret.append((char) (y2 + '1'));
      if (move.promoteTo != Piece.EMPTY) ret.append(pieceToChar(move.promoteTo));
    }
    UndoInfo ui = new UndoInfo();
    pos.makeMove(move, ui);
    boolean givesCheck = MoveGen.inCheck(pos);
    if (givesCheck) {
      ArrayList<Move> nextMoves = MoveGen.instance.pseudoLegalMoves(pos);
      // this should not be needed here
      // nextMoves = MoveGen.removeIllegal(pos, nextMoves);
      if (nextMoves.size() == 0) {
        ret.append('#');
      } else {
        ret.append('+');
      }
    }
    pos.unMakeMove(move, ui);

    return ret.toString();
  }
Esempio n. 4
0
  /** Parse a FEN string and return a chess Position object. */
  public static final Position readFEN(String fen) throws ChessParseError {
    Position pos = new Position();
    String[] words = fen.split(" ");
    if (words.length < 2) {
      throw new ChessParseError(R.string.err_too_few_spaces);
    }
    for (int i = 0; i < words.length; i++) {
      words[i] = words[i].trim();
    }

    // Piece placement
    int row = 7;
    int col = 0;
    for (int i = 0; i < words[0].length(); i++) {
      char c = words[0].charAt(i);
      switch (c) {
        case '1':
          col += 1;
          break;
        case '2':
          col += 2;
          break;
        case '3':
          col += 3;
          break;
        case '4':
          col += 4;
          break;
        case '5':
          col += 5;
          break;
        case '6':
          col += 6;
          break;
        case '7':
          col += 7;
          break;
        case '8':
          col += 8;
          break;
        case '/':
          row--;
          col = 0;
          break;
        case 'P':
          safeSetPiece(pos, col, row, Piece.WPAWN);
          col++;
          break;
        case 'N':
          safeSetPiece(pos, col, row, Piece.WKNIGHT);
          col++;
          break;
        case 'B':
          safeSetPiece(pos, col, row, Piece.WBISHOP);
          col++;
          break;
        case 'R':
          safeSetPiece(pos, col, row, Piece.WROOK);
          col++;
          break;
        case 'Q':
          safeSetPiece(pos, col, row, Piece.WQUEEN);
          col++;
          break;
        case 'K':
          safeSetPiece(pos, col, row, Piece.WKING);
          col++;
          break;
        case 'p':
          safeSetPiece(pos, col, row, Piece.BPAWN);
          col++;
          break;
        case 'n':
          safeSetPiece(pos, col, row, Piece.BKNIGHT);
          col++;
          break;
        case 'b':
          safeSetPiece(pos, col, row, Piece.BBISHOP);
          col++;
          break;
        case 'r':
          safeSetPiece(pos, col, row, Piece.BROOK);
          col++;
          break;
        case 'q':
          safeSetPiece(pos, col, row, Piece.BQUEEN);
          col++;
          break;
        case 'k':
          safeSetPiece(pos, col, row, Piece.BKING);
          col++;
          break;
        default:
          throw new ChessParseError(R.string.err_invalid_piece, pos);
      }
    }
    if (words[1].length() == 0) {
      throw new ChessParseError(R.string.err_invalid_side, pos);
    }
    pos.setWhiteMove(words[1].charAt(0) == 'w');

    // Castling rights
    int castleMask = 0;
    if (words.length > 2) {
      for (int i = 0; i < words[2].length(); i++) {
        char c = words[2].charAt(i);
        switch (c) {
          case 'K':
            castleMask |= (1 << Position.H1_CASTLE);
            break;
          case 'Q':
            castleMask |= (1 << Position.A1_CASTLE);
            break;
          case 'k':
            castleMask |= (1 << Position.H8_CASTLE);
            break;
          case 'q':
            castleMask |= (1 << Position.A8_CASTLE);
            break;
          case '-':
            break;
          default:
            throw new ChessParseError(R.string.err_invalid_castling_flags, pos);
        }
      }
    }
    pos.setCastleMask(castleMask);
    removeBogusCastleFlags(pos);

    if (words.length > 3) {
      // En passant target square
      String epString = words[3];
      if (!epString.equals("-")) {
        if (epString.length() < 2) {
          throw new ChessParseError(R.string.err_invalid_en_passant_square, pos);
        }
        pos.setEpSquare(getSquare(epString));
      }
    }

    try {
      if (words.length > 4) {
        pos.halfMoveClock = Integer.parseInt(words[4]);
      }
      if (words.length > 5) {
        pos.fullMoveCounter = Integer.parseInt(words[5]);
      }
    } catch (NumberFormatException nfe) {
      // Ignore errors here, since the fields are optional
    }

    // Each side must have exactly one king
    int[] nPieces = new int[Piece.nPieceTypes];
    for (int i = 0; i < Piece.nPieceTypes; i++) nPieces[i] = 0;
    for (int x = 0; x < 8; x++)
      for (int y = 0; y < 8; y++) nPieces[pos.getPiece(Position.getSquare(x, y))]++;
    if (nPieces[Piece.WKING] != 1) throw new ChessParseError(R.string.err_white_num_kings, pos);
    if (nPieces[Piece.BKING] != 1) throw new ChessParseError(R.string.err_black_num_kings, pos);

    // White must not have too many pieces
    int maxWPawns = 8;
    maxWPawns -= Math.max(0, nPieces[Piece.WKNIGHT] - 2);
    maxWPawns -= Math.max(0, nPieces[Piece.WBISHOP] - 2);
    maxWPawns -= Math.max(0, nPieces[Piece.WROOK] - 2);
    maxWPawns -= Math.max(0, nPieces[Piece.WQUEEN] - 1);
    if (nPieces[Piece.WPAWN] > maxWPawns)
      throw new ChessParseError(R.string.err_too_many_white_pieces, pos);

    // Black must not have too many pieces
    int maxBPawns = 8;
    maxBPawns -= Math.max(0, nPieces[Piece.BKNIGHT] - 2);
    maxBPawns -= Math.max(0, nPieces[Piece.BBISHOP] - 2);
    maxBPawns -= Math.max(0, nPieces[Piece.BROOK] - 2);
    maxBPawns -= Math.max(0, nPieces[Piece.BQUEEN] - 1);
    if (nPieces[Piece.BPAWN] > maxBPawns)
      throw new ChessParseError(R.string.err_too_many_black_pieces, pos);

    // Make sure king can not be captured
    Position pos2 = new Position(pos);
    pos2.setWhiteMove(!pos.whiteMove);
    if (MoveGen.inCheck(pos2)) {
      throw new ChessParseError(R.string.err_king_capture_possible, pos);
    }

    fixupEPSquare(pos);

    return pos;
  }